我正在使用正则表达式,我想在Java的String类的replaceAll
方法中使用它。
我的正则表达式工作正常并且groupCount()
返回11.因此,当我尝试使用指向第11组的反向引用替换我的文本时,我得到第一组带有" 1"附在上面,而不是十一组。
String regex = "(>[^<]*?)((\+?\d{1,4}[ \t\f\-\.](\d[ \t\f\-\.])?)?(\(\d{1,4}([\s-]\d{1,4})?\)[\.\- \t\f])?((\d{2,6}[\.\- \t\f])+\d{2,6})|(\d{6,16})([;,\.]{1,3}\d{3,}#?)?)([^<]*<)";
String text = "<span style=\"font-size:11.0pt\">675-441-3144;;;78888464#<o:p></o:p></span>":
String replacement = text.replaceAll(regex, $1<a href="tel:$2">$2</a>$11");
我希望得到以下结果:
<span style=\"font-size:11.0pt\"><a href=\"tel:675-441-3144;;;78888464#\">675-441-3144;;;78888464#</a><o:p></o:p></span>
但11美元的反向引用没有返回第11组,它返回第一组附加1,而是得到以下结果:
<span style="font-size:11.0pt"><a href="tel:675-441-3144">675-441-3144</a>>1o:p></o:p></span>
有人可以告诉我如何访问我的第11组模式吗?
感谢。
答案 0 :(得分:2)
您在替换中访问第11组比赛的方式是使用$11
。
正如corresponding Javadoc *所述:
替换字符串可能包含对捕获的子序列的引用 在上一场比赛中:每次出现
${name}
或$g
都是 替换为评估相应group(name)或的结果 分别为group(g)。对于$g
,$
之后的第一个数字始终为 作为小组参考的一部分处理。随后的数字是 如果它们构成法律小组参考,则纳入g
。
所以一般来说,只要至少有11个组,那么"$11"
将评估为group(11)
。但是,如果您没有至少11个群组,则"$11"
将评估为group(1) + "1"
。
* 此引文来自Matcher#appendReplacement(StringBuffer,String)
,这是String#replaceAll(String,String)
引用的相关引用链。
你的正则表达式不符合你的想法。
让我们将你的正则表达式划分为三个顶级组。这些分别是第1,2和11组。
(>[^<]*?)
((\+?\d{1,4}[ \t\f\-\.](\d[ \t\f\-\.])?)?(\(\d{1,4}([\s-]\d{1,4})?\)[\.\- \t\f])?((\d{2,6}[\.\- \t\f])+\d{2,6})|(\d{6,16})([;,\.]{1,3}\d{3,}#?)?)
([^<]*<)
第2组是正则表达式的主体,它包含两个选项的顶级交替。这两个选项分别由3-8组和9-10组组成。
((\+?\d{1,4}[ \t\f\-\.](\d[ \t\f\-\.])?)?(\(\d{1,4}([\s-]\d{1,4})?\)[\.\- \t\f])?((\d{2,6}[\.\- \t\f])+\d{2,6})
(\d{6,16})([;,\.]{1,3}\d{3,}#?)?)
现在,给定text
字符串,这是正在发生的事情:
">"
匹配。"675-441-3144"
匹配。"675-441-3144"
。"675-441-3144"
之后,紧接在";;;78888464#"
之前。"<"
的所有内容,";;;78888464#<"
。因此,您希望在第2组中的某些内容实际上是在第11组中。
执行以下两项操作:
从
转换第2组的内容option1|option2
到
option1(option2)?|option2
将替换模式中的$11
更改为$12
。
这将贪婪匹配一个或两个选项,而不是只有一个选项。对替换模式的修改是因为我们添加了一个组。
现在我们已经修改了正则表达式,我们原来的&#34;选项2&#34;不再有意义。鉴于我们的新模式模板option1(option2)?|option2
,第2组将无法匹配"675-441-3144;;;78888464#"
。这是因为我们原来的选项1&#34;将匹配所有"675-441-3144"
,然后停止。我们的原始&#34;选项2&#34;然后将尝试匹配";;;78888464#"
,但无法匹配,因为它以6-10位数的强制捕获组开头:(\d{6,16})
,但";;;78888464#"
以分号开头。
转换原始&#34;选项2&#34;的内容从
(\d{6,16})([;,\.]{1,3}\d{3,}#?)?
到
([;,\.]{1,3}\d{3,}#?)?
我们有一个最后要解决的问题。现在,我们原来的&#34;选项2&#34;仅包含具有?
量词的单个组,它可以成功匹配零长度子字符串。因此,我们的模板模板option1(newoption2)?|newoption2
可能导致零长度匹配,这不符合匹配电话号码的预期目的。
执行以下两项操作:
转换新&#34;选项2&#34;的内容从
(〔;,] {1,3} \ d {3,}#)?
到
〔;,] {1,3} \ d {3,}#
将替换字符串中的$12
更改为$10
,因为我们现在已在两个位置删除了一个组。
将所有内容放在一起,我们的最终解决方案如下。
搜索正则表达式:
(>[^<]*?)((\+?\d{1,4}[ \t\f\-\.](\d[ \t\f\-\.])?)?(\(\d{1,4}([\s-]\d{1,4})?\)[\.\- \t\f])?((\d{2,6}[\.\- \t\f])+\d{2,6})([;,\.]{1,3}\d{3,}#?)?|[;,\.]{1,3}\d{3,}#?)([^<]*<)
替换正则表达式:
$1<a href="tel:$2">$2</a>$10
<强>爪哇:强>
final String searchRegex = "(>[^<]*?)((\\+?\\d{1,4}[ \\t\\f\\-\\.](\\d[ \\t\\f\\-\\.])?)?(\\(\\d{1,4}([\\s-]\\d{1,4})?\\)[\\.\\- \\t\\f])?((\\d{2,6}[\\.\\- \\t\\f])+\\d{2,6})([;,\\.]{1,3}\\d{3,}#?)?|[;,\\.]{1,3}\\d{3,}#?)([^<]*<)";
final String replacementRegex = "$1<a href=\"tel:$2\">$2</a>$10";
String text = "<span style=\"font-size:11.0pt\">675-441-3144;;;78888464#<o:p></o:p></span>";
String replacement = text.replaceAll(searchRegex, replacementRegex);
答案 1 :(得分:-1)
好吧,在尝试使用replaceall做到没有成功之后,我不得不自己实现替换方法:
public static String parsePhoneNumbers(String html){
StringBuilder regex = new StringBuilder(120);
regex.append("(>[^<]*?)(")
.append("((\+?\d{1,4}[ \t\f\-\.](\d[ \t\f\-\.])?)?")
.append("(\(\d{1,4}([\s-]\d{1,4})?\)[\.\- \t\f])?")
.append("((\d{2,6}[\.\- \t\f])+\d{2,6})|(\d{6,16})")
.append("([;,\.]{1,3}\d{3,}#?)?)")
.append(")+([^<]*<)");
StringBuilder mutableHtml = new StringBuilder(html.length());
Pattern pattern = Pattern.compile(regex.toString());
Matcher matcher = pattern.matcher(html);
int start = 0;
while(matcher.find()){
mutableHtml.append(html.substring(start, matcher.start()));
mutableHtml.append(matcher.group(1)).append("<a href=\"tel:")
.append(matcher.group(2)).append("\">").append(matcher.group(2))
.append("</a>").append(matcher.group(matcher.groupCount()));
start = matcher.end();
}
mutableHtml.append(html.substring(start));
return mutableHtml.toString();
}