gpt4 book ai didi

java - Java正则表达式向后引用两位数

转载 作者:行者123 更新时间:2023-12-02 03:07:24 33 4
gpt4 key购买 nike

我正在使用正则表达式,并且想在Java中String类的replaceAll方法上使用它。

我的正则表达式可以正常工作,并且groupCount()返回11。因此,当我尝试使用指向第11个组的后向引用替换文本时,我得到的第一个组带有附加的“ 1”,而不是第11个组。

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组吗?

谢谢。

最佳答案

简短答案

在替换中,您访问比赛第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部分

问题

让我们将正则表达式分为三个顶级组。这些分别是组1、2和11。


第一组:
(>[^<]*?)
第2组:
((\+?\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,}#?)?)
第11组:
([^<]*<)


第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字符串,这是怎么回事:


组1执行。它匹配第一个">"
第2组执行。它按顺序评估其交替的选项。


执行第2组交替的第一个选项。它匹配"675-441-3144"
第2组的轮换在其选项之一匹配时成功短路。


现在,第2组整体等于匹配的选项,即"675-441-3144"
现在,光标位于"675-441-3144"之后,也就是";;;78888464#"之前。


第11组执行。它匹配下一个"<"中所有的所有内容。


因此,您希望放在第2组中的某些内容实际上是在第11组中。

解决方案

请同时执行以下两项操作:


将第2组的内容转换为

option1|option2




option1(option2)?|option2

将替换模式中的 ";;;78888464#<"更改为 $11


这会使贪婪地匹配一个或两个选项,而不是只有一个选项。替换模式的修改是因为我们添加了一个组。

第2部分

问题

现在,我们已经修改了正则表达式,原来的“选项2”不再有意义。给定我们新的模式模板 $12,第2组将不可能匹配 option1(option2)?|option2。这是因为我们原始的“选项1”将匹配所有 "675-441-3144;;;78888464#",然后停止。然后,我们原来的“选项2”将尝试匹配 "675-441-3144",但是将无法匹配,因为它以6-10位数字的强制捕获组开头: ";;;78888464#",而 (\d{6,16})以分号开头。

解决方案

将原始“选项2”的内容转换为

(\d{6,16})([;,\.]{1,3}\d{3,}#?)?




([;,\.]{1,3}\d{3,}#?)?


第三部分

问题

我们还有最后一个问题要解决。既然我们原来的“选项2”仅由带有 ";;;78888464#"量词的单个组组成,就有可能成功匹配零长度子串。因此,我们的模式模板 ?可能会导致长度为零的匹配,这不能满足匹配电话号码的预期目的。

解决方案

请执行以下两个操作:


将新的“选项2”的内容转换为

([;,。] {1,3} \ d {3,}#?)?



[;,。] {1,3} \ d {3,}#?
将替换字符串中的 option1(newoption2)?|newoption2更改为 $12,因为现在已经在两个位置删除了一个组。




最终的解决方案

综上所述,我们的最终解决方案如下。

搜索正则表达式:

(>[^<]*?)((\+?\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


Java:

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);


Proof of correctness

关于java - Java正则表达式向后引用两位数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41562525/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com