49

在 Java 中,似乎在其他一些语言中,模式中的反向引用前面有一个反斜杠(例如\1, \2,\3等),但在替换字符串中它们前面有一个美元符号(例如$1, $2, $3, and also $0)。

这是一个片段来说明:

System.out.println(
    "left-right".replaceAll("(.*)-(.*)", "\\2-\\1") // WRONG!!!
); // prints "2-1"

System.out.println(
    "left-right".replaceAll("(.*)-(.*)", "$2-$1")   // CORRECT!
); // prints "right-left"

System.out.println(
    "You want million dollar?!?".replaceAll("(\\w*) dollar", "US\\$ $1")
); // prints "You want US$ million?!?"

System.out.println(
    "You want million dollar?!?".replaceAll("(\\w*) dollar", "US$ \\1")
); // throws IllegalArgumentException: Illegal group reference

问题:

  • 在替换字符串中使用$for 反向引用是 Java 独有的吗?如果不是,是什么语言开始的?什么口味使用它,什么不使用?
  • 为什么这是个好主意?为什么不坚持相同的模式语法?这不会导致语言更有凝聚力和更容易学习吗?
    • 如果上面的语句 1 和 4 是“正确”语句而不是 2 和 3,那么语法会不会更精简?
4

2 回答 2

35

在替换字符串中使用 $ 进行反向引用是 Java 独有的吗?

不。Perl 使用它,而且 Perl 肯定早于 Java 的Pattern类。Java 的正则表达式支持是根据 Perl 正则表达式明确描述的。

例如: http: //perldoc.perl.org/perlrequick.html#Search-and-replace

为什么这是个好主意?

很明显,您认为这不是一个好主意!但它是一个好主意的一个原因是使 Java 搜索/替换支持(更多)与 Perl 兼容。

还有另一个可能的原因$可能被视为比\. 那就是\必须像\\Java String 文字那样编写。

但这一切纯属猜测。做出设计决定时,我们都没有在房间里。最终,他们为什么以这种方式设计替换 String 语法并不重要。这些决定已经做出并具体化,任何进一步的讨论都是纯粹的学术性的……除非你碰巧正在为 Java 设计一种新语言或新的正则表达式库。

于 2010-05-23T05:03:03.017 回答
20

在做了一些研究之后,我现在理解了这些问题:Perl必须为模式反向引用和替换反向引用使用不同的符号,虽然不必java.util.regex.*效仿,但它选择这样做,不是出于技术原因,而是出于传统原因。


在 Perl 方面

(请记住,我目前对 Perl 的所有了解都来自阅读 Wikipedia 文章,因此请随时纠正我可能犯的任何错误)

在 Perl 中必须这样做的原因如下:

  • Perl$用作符号(即附加到变量名的符号)。
  • Perl 字符串文字是变量插值。
  • Perl 正则表达式实际上将组捕获为变量$1,$2等。

因此,由于 Perl 的解释方式及其正则表达式引擎的工作方式,\1必须在模式中使用前面的斜线来表示反向引用(例如 ),因为如果使用 sigil$代替(例如$1),它会导致意外的变量插值到图案。

替换字符串,由于它在 Perl 中的工作方式,在每个匹配的上下文中进行评估。Perl 在这里使用变量插值是最自然的,因此正则表达式引擎将组捕获到变量$1,$2等中,以使其与语言的其余部分无缝协作。

参考


在 Java 方面

Java 是一种与 Perl 非常不同的语言,但这里最重要的是没有变量插值。此外,replaceAll是一个方法调用,与 Java 中的所有方法调用一样,参数在调用方法之前被评估一次。

因此,变量插值功能本身是不够的,因为本质上必须在每次匹配时重新评估替换字符串,而这不是 Java 中方法调用的语义。在调用之前评估的变量插值替换字符串实际上是无用的;replaceAll插值需要在方法期间,在每场比赛中发生。

由于这不是 Java 语言的语义,因此必须手动replaceAll进行这种“即时”插值。因此,绝对没有技术原因为什么替换字符串中的反向引用的转义符号。它很可能是. 相反,模式中的反向引用也可以使用而不是进行转义,并且在技术上它仍然可以正常工作。$\$\

Java 以它的方式进行正则表达式的原因纯粹是传统的:它只是遵循 Perl 设定的先例。

于 2010-05-23T06:20:26.357 回答