replacestring中的反向引用语法(为什么是美元符号?)

在Java中,似乎在其他一些语言中,模式中的反向引用前面有一个反斜杠(例如\1\2\3等),但是在replacestring中,它们前面是美元符号(例如$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中使用独特的replacestring反向引用$ ? 如果不是,什么语言开始呢? 什么味道使用它,什么不使用?
  • 为什么这是一个好主意? 为什么不坚持相同的模式语法? 这不会导致更有凝聚力和更容易学习的语言吗?
    • 如果上面的语句1和4是“正确的”而不是2和3,语法是不是会更简化?

在Java中使用独特的replacestring反向引用$?

不,Perl使用它,而且Perl早于Java的Pattern类。 Java的正则expression式支持是用Perl正则expression式来明确描述的。

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

为什么这是一个好主意?

显然,你不认为这是一个好主意! 但是,一个好主意的原因是让Javasearch/replace支持(更多)与Perl兼容。

还有另一个可能的原因,为什么$可能被视为比\更好的select。 那就是\必须写成\\在Java String文字中。

但所有这些都是纯粹的猜测。 在做出devise决定时,我们没有人在场。 最终,他们为什么以这种方式devise替代的String语法并不重要。 这些决定已经被制定和具体化,任何进一步的讨论纯粹是学术的,除非你碰巧正在为Javadevise一种新的语言或新的正则expression式库。

在做了一些研究之后,我已经了解了这些问题:Perl 必须使用不同的符号来进行模式反向引用和replace反向引用,而java.util.regex.*则不必遵循,它会select一个技术性而非传统的理由。


在Perl方面

(请记住,现在我所知道的关于Perl的知识都来自于维基百科的文章,所以请随时纠正我可能犯的错误)

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

  • Perl使用$作为签名(即附加到variables名称的符号)。
  • Perlstring文字是可变插值的。
  • Perl的正则expression式实际上捕获组variables$1$2

因此,由于Perl被解释的方式以及它的正则expression式引擎是如何工作的,所以必须使用前面的反向引用斜线(例如\1 ),因为如果使用sigil $ (例如$1 ),会导致意外可变插值到模式中。

replacestring,由于它在Perl中的工作原理,在每个匹配的上下文中进行评估。 Perl在这里使用可变插值是最自然的,因此正则expression式引擎将组捕获到variables$1$2等中,以使其与其余语言无缝地工作。

参考

  • 维基百科/string文字 – 可变插值
  • 维基百科/ Sigil(电脑编程)

在Java方面

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

因此,variables插值function本身是不够的,因为实质上replacestring必须在每次匹配时重新计算,这不仅仅是Java中的方法调用的语义。 在replaceAll被调用之前求值的variables插值replacestring实际上是无用的; 在每个匹配的方法中都需要进行插值。

由于这不是Java语言的语义,因此replaceAll必须手动执行此“即时”插值。 因此, 绝对没有技术原因,为什么$是replacestring反向引用的逃避符号。 这可能是很好的\ 。 相反,模式中的反向引用也可以用$而不是\来逃脱,并且它在技术上仍然可以工作。

Java所采用的方式是纯粹的传统:它只是遵循Perl设定的先例。