Java中的正则表达式反向引用
Posted
技术标签:
【中文标题】Java中的正则表达式反向引用【英文标题】:Regex backreferences in Java 【发布时间】:2018-07-13 12:13:56 【问题描述】:我必须匹配一个数字后跟它本身 14 次。然后我来到regexstor.net/tester中的如下正则表达式:
(\d)\114
编辑
当我将它粘贴到我的代码中时,包括正确的反斜杠:
"(\\d)\\114"
我已将反向引用 "\1"
替换为 "$1"
,它用于在 Java 中替换匹配项。
然后我意识到它不起作用。当你需要在 REGEX 中反向引用一个匹配时,在 Java 中,你必须使用"\N"
,但是当你想替换它时,操作符是"$N"
。
我的问题是:为什么?
【问题讨论】:
这不仅仅是 Java,在大多数正则表达式风格中,\N
是正则表达式模式中的反向引用。 $
在正则表达式中有特殊含义
是的,“$”表示表达式的结束,但是为什么他们不用\N
来代替呢?
其中一些像 python
、sed
或 perl
确实允许 \N
替换,但 Java 设计人员决定使用 $
表示法
【参考方案1】:
$1
不是 Java 正则表达式中的反向引用,也不是我能想到的任何其他风格。只有在替换某些东西时才使用$1
:
String input="A12.3 bla bla my input";
input = StringUtils.replacePattern(
input, "^([A-Z]\\d2\\.\\d).*$", "$1");
// ^^^^
关于什么是反向引用存在一些错误信息,包括我从以下位置获得 sn-p 的地方:simple java regex with backreference does not work。
Java 模仿其他现有风格的正则表达式语法,其中 $
已经是元字符。它锚定到字符串的末尾(或多行模式下的行)。
同样,Java 使用\1
进行反向引用。因为正则表达式是字符串,所以必须转义:\\1
。
从词汇/句法的角度来看,$1
确实可以明确使用(作为奖励,它可以防止在使用反向引用时需要“邪恶的逃逸转义”)。
要匹配行尾之后的1
,正则表达式需要是$\n1
:
this line
1
使用熟悉的语法而不是更改规则更有意义,其中大部分来自 Perl。
Perl 的第一个版本出现在1987,比 Java 早得多,Java 的 beta 版本在1995 发布。
我挖出了man pages for Perl 1,上面写着:
也可以使用括号构造
(\ ...\ )
,在这种情况下\<digit>
匹配digit
'th 子字符串。 (在模式之外,请始终在数字前使用$
而不是\
。$<digit>
(和$\`
、$&
和$&
和$'
)的范围延伸到封闭BLOCK 的末尾或 eval 字符串,或与子表达式匹配的下一个模式。\<digit>
表示法有时在当前模式之外工作,但不应依赖。)你可以有尽可能多的括号。如果您有超过 9 个子字符串,则变量$10
、$11
、... 指的是对应的子字符串。在模式中,\10
、\11
等如果在反向引用之前至少有那么多左括号,则引用回子字符串。否则(为了向后兼容)\10
与\010
相同,一个退格,\11
与\011
相同,一个制表符。等等。 (\1
到\9
始终是反向引用。)
【讨论】:
“Java 在 $ 已经是元字符的其他现有风格之后对其正则表达式语法建模。它锚定到字符串的末尾(或多行模式下的行)”是有道理的。你有任何来源吗? @Jaumzera 我现在做 ;) 我不知道什么是“evil escaped escape”,你能提供一个链接吗? @Raining 在其他正则表达式风格中,您可以只有一个转义字符:\1
。在 Java 中,您必须逃脱该转义:\\1
。这显然是邪恶的。
@Laurel 你救了我的命。我不知道在 Java 中数字引用必须用双杠 \\...我同意,这显然是邪恶的哈哈。【参考方案2】:
我认为主要问题不是反向引用——它在 java 中与 \1
完美配合。
您的问题更可能是 Java 中正则表达式模式的“整体”转义。
如果你想拥有图案
(\d)\114
传递给正则表达式引擎,您首先需要对其进行转义,因为在您编写它时它是一个 java 字符串:
(\\d)\\114
瞧,就像一个魅力:goo.gl/BNCx7B(添加 http://,SO 不允许 Url-Shorteners,但 tutorialspoint.com 似乎没有其他选择)
离线示例:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HelloWorld
public static void main(String []args)
String test = "555555555555555"; // 5 followed by 5 for 14 times.
String pattern = "(\\d)\\114";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(test);
if (m.find( ))
System.out.println("Matched!");
else
System.out.println("not matched :-(");
【讨论】:
感谢您的关注,@dognose。我确实知道 Java 中的字符串/正则表达式转义。我意识到我应该把它放在问题中。我正在编辑它。 @Jaumzera 只需查看我提供的示例 - 如果转义模式不起作用 - 那么您的错误在其他地方,但不在“模式”内。 (你确定你有 15 次相同的数字吗?(因为你说 1 + 14 个追随者)——而不只是总共 14 个?) 好吧,我明白你的意思了。但我的疑问是替换运算符本身而不是正则表达式。谢谢你的时间。 +一个。 如果我使用([0-9]2-)\\12[0-9]2
或 ([0-9]2)-\\1-\\1-\\1
对我不起作用以上是关于Java中的正则表达式反向引用的主要内容,如果未能解决你的问题,请参考以下文章