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来代替呢? 其中一些像 pythonsedperl 确实允许 \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中的正则表达式反向引用的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式反向引用乘法[重复]

正则表达式;反向引用字符集中不匹配的字符

在 sed 中使用反向引用正则表达式

正则——反向引用

java中的正则表达式

PHP正则表达式 - 替换一个反向引用[重复]