Java中的正则表达式反向引用

6

我需要匹配一个数字,然后这个数字需要连续出现14次。在regexstor.net/tester上,我找到了以下正则表达式:

(\d)\1{14}

编辑

当我将其包括反斜杠正确地粘贴到我的代码中:

"(\\d)\\1{14}"

我已经将反向引用“\1”替换为在Java中用于替换匹配项的“$1”。然后我意识到它不起作用。在Java中,当您需要反向引用正则表达式中的匹配项时,必须使用“\N”,但是当您想要替换它时,运算符是“$N”。我的问题是:为什么?

1
这不仅仅是Java,大多数正则表达式中\N是正则表达式模式中的反向引用。$在正则表达式中有特殊含义。 - anubhava
是的,"$"表示表达式的结尾,但为什么他们不使用“\N”来替换呢? - Jaumzera
其中一些像 pythonsedperl 允许在替换中使用 \N,但 Java 设计者决定使用 $ 符号。 - anubhava
2个回答

10

$1不是Java正则表达式中的反向引用,也不是我能想到的任何其他风格。你只在替换内容时使用$1

String input="A12.3 bla bla my input";
input = StringUtils.replacePattern(
            input, "^([A-Z]\\d{2}\\.\\d).*$", "$1");
//                                            ^^^^

关于后向引用(back reference)有一些错误的信息,包括我从这里得到的代码片段:simple java regex with backreference does not work


Java参照了其他已存在的正则表达式语法,其中$已经是元字符。它锚定在字符串的结尾(或在多行模式下锚定在行末)。

类似地,Java使用\1表示后向引用。因为正则表达式是字符串,所以必须进行转义:\\1

从词汇/语法的角度来看,$1也可以被明确地使用(作为奖励,它将消除使用后向引用时“恶意转义”的需要)。

要匹配在行末之后的数字1,正则表达式应该是$\n1

this line
1

使用熟悉的语法比改变规则更有意义,大多数规则都来自Perl。

Perl的第一个版本发布于1987年,比Java早得多,Java在1995年发布beta版。

我找到了Perl 1的man页,上面写着:

括号构造(\ ...\ )也可以用,此时\<digit>匹配第digit个子字符串。(在模式外部,始终使用$而不是\前面加数字。变量$<digit>(以及$\`$&$')的作用范围延伸到封闭块或eval字符串的末尾,或者到具有子表达式的下一个模式匹配为止。 \<digit>表示法有时在当前模式之外起作用,但不应依赖它。)您可以拥有任意数量的括号。如果您有多于9个子字符串,则变量$10$11等引用相应的子字符串。在模式内部,\10\11等引用回到子字符串(如果在反向引用之前至少有这么多个左括号)。否则(为了向后兼容性),\10与后退相同,即退格,\11与制表符相同。等等。(\1\9始终是反向引用。)


“Java 模仿了其他已有的正则表达式语法,其中 $ 已经是元字符。它锚定到字符串的末尾(或在多行模式下锚定到行的末尾)”这句话说得通。你有任何来源吗? - Jaumzera
1
@Jaumzera 我现在知道了 ;) - Laurel
我不知道什么是“evil escaped escape”,您能提供一个链接吗? - VimNing
1
在其他正则表达式风格中,你只需要一个转义字符:\1。但是在Java中,你必须转义这个转义符:\\1。这显然很麻烦。 - Laurel
@Laurel,你救了我的命。我不知道在Java中,数字引用必须使用双杠\进行转义...我同意,这显然是邪恶的哈哈。 - malkomich

3

我认为主要问题不在于反向引用——在Java中使用\1完全没有问题。

你的问题更可能是Java中正则表达式模式的“整体”转义。

如果你想要这个模式:

(\d)\1{14}

当你把一个字符串传递给正则表达式引擎时,首先你需要对它进行转义,因为在你编写它时,它是一个Java字符串:

(\\d)\\1{14}

非常好,像魔法一样奏效: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)\\1{14}";

        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中的String/Regex转义。我意识到我应该把它放在问题中。我正在编辑它。 - Jaumzera
@Jaumzera,只需查看我提供的示例-如果转义模式不起作用,则您的错误在其他地方,而不是“模式”中。(您确定您有15次相同的数字吗?(因为您说1 + 14个关注者)-而不仅仅是总共14个吗?) - dognose
好的,我明白你的意思了。但是我的疑问是关于替换运算符本身,而不是正则表达式。感谢你的时间。+1。 - Jaumzera
如果我使用([0-9]{2}-)\\1{2}[0-9]{2}([0-9]{2})-\\1-\\1-\\1,对我不起作用。 - JGFMK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接