java-替换字符串中的反向引用语法(为什么要用美元符号?)

在Java中,并且似乎在其他几种语言中,模式中的反向引用前面带有反斜杠(例如$\2\3等),但是在替换字符串中,它们前面带有美元符号(例如$1$2$3 ,以及$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

问题:

  • 在Java独有的替换字符串中使用$作为反向引用吗? 如果没有,用什么语言开始的? 什么口味使用它,什么不使用?
  • 为什么这是个好主意? 为什么不坚持相同的模式语法? 这会不会导致语言的衔接性和学习性更强?
    • 如果上面的语句1和4是“正确的”语句而不是2和3,那么语法是否会更加简化?
2个解决方案
33 votes

在Java独有的替换字符串中,使用$作为反向引用吗?

不,Perl使用它,Perl肯定早于Java的$类。 Java的regex支持是根据Perl regexes明确描述的。

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

为什么这是个好主意?

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

还有另一个可能的原因,为什么$被视为比\更好的选择。也就是说,必须在Java String文字中将\编写为\\

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

Stephen C answered 2020-07-02T09:39:31Z
19 votes

经过研究后,我现在已经了解了这些问题:Perl必须对模式反向引用和替换反向引用使用不同的符号,而$1不必遵循,但它选择这样做不是出于技术原因而是出于传统原因 。


在Perl方面

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

在Perl中必须以这种方式完成此操作的原因如下:

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

因此,由于Perl的解释方式及其正则表达式引擎的工作方式,因此必须在模式中使用反向引用的斜杠(例如replaceAll),因为如果使用符号$(例如\),则会导致意外的变量 插值到模式中。

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

参考资料

  • Wikipedia /字符串文字-变量插值
  • Wikipedia / Sigil(计算机编程)

在Java方面

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

因此,变量插值功能本身是不够的,因为本质上必须在每次匹配时都重新评估替换字符串,而这并不是Java中方法调用的语义。 实际上,在调用replaceAll之前评估的可变插值替换字符串实际上是没有用的; 插值需要在方法中每次匹配时进行。

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

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

polygenelubricants answered 2020-07-02T09:41:05Z
translate from https://stackoverflow.com:/questions/2890700/backreferences-syntax-in-replacement-strings-why-dollar-sign