为什么java中的String.replaceAll()需要在正则表达式中使用4个斜杠"\\\\"来实际替换"\"?

Bha*_*ath 27 java regex string escaping charsequence

我最近注意到,当涉及转义字符"\"(斜杠)时,String.replaceAll(正则表达式,替换)表现得非常奇怪.

例如,考虑有一个与文件路径字符串- String text = "E:\\dummypath" 我们要替换的"\\""/".

text.replace("\\","/")给出输出"E:/dummypath",然后text.replaceAll("\\","/")引发异常java.util.regex.PatternSyntaxException.

如果我们想要实现相同的功能,replaceAll()我们需要将其编写为, text.replaceAll("\\\\","/")

一个值得注意的区别是replaceAll()它的参数是reg-ex而replace()有参数字符序列!

text.replaceAll("\n","/")其作用与其char序列完全相同text.replace("\n","/")

深入挖掘: 当我们尝试其他一些输入时,可以观察到更奇怪的行为.

让我们分配 text="Hello\nWorld\n"

现在 text.replaceAll("\n","/"),text.replaceAll("\\n","/"),text.replaceAll("\\\n","/")这三个提供同样的输出Hello/World/

Java以我认为最好的方式搞砸了reg-ex!没有其他语言似乎在reg-ex中具有这些有趣的行为.任何特定的原因,为什么Java搞砸了这样?

Pet*_*rey 26

你需要esacpe两次,一次用于Java,一次用于正则表达式.

Java代码是

"\\\\"
Run Code Online (Sandbox Code Playgroud)

制作一个正则表达式的字符串

"\\" - two chars
Run Code Online (Sandbox Code Playgroud)

但正则表达式也需要逃避,所以它变成了

\ - one symbol
Run Code Online (Sandbox Code Playgroud)

  • `\n`是普通的换行符,这个转换是在编译时.`\\n`告诉正则表达式模式处理器解码换行符,它在运行时执行.`\\\n`表示将`\n`作为文字.这最终会以更复杂的方式成为同一件事.有多种方法可以做到这一点的原因是,所有文字字符都支持`\\`,恰好适用于字面意义上的字符. (2认同)

Ste*_*n C 23

@Peter Lawrey的回答描述了这些机制."问题"是反斜杠是Java字符串文字和正则表达式的迷你语言中的转义字符.因此,当您使用字符串文字来表示正则表达式时,有两组转义需要考虑...取决于您希望正则表达式的含义.

但为什么会那样?

这是历史性的事情.Java最初根本没有正则表达式.Java字符串文字的语法规则是从C/C++中借用的,它也没有内置的正则表达式支持.Pattern在Java 1.4 中以类的形式添加正则表达式支持之前,双重转义的尴尬在Java中并不明显.

那么其他语言如何设法避免这种情况呢?

他们通过在编程语言本身中为正则表达式提供直接或间接的语法支持来实现.例如,在Perl,Ruby,Javascript和许多其他语言中,有一种模式/正则表达式的语法(例如'/ pattern /'),其中字符串文字转义规则不适用.在C#和Python中,它们提供了另一种"原始"字符串文字语法,其中反斜杠不会转义.(但请注意,如果使用普通的C#/ Python字符串语法,则存在双重转义的Java问题.)


为什么text.replaceAll("\n","/"),text.replaceAll("\\n","/")以及 text.replaceAll("\\\n","/")所有给予相同的输出?

第一种情况是字符串级别的换行符.Java正则表达式语言将所有非特殊字符视为自己匹配.

第二种情况是反斜杠,后跟字符串级别的"n".Java正则表达式语言解释反斜杠后跟"n"作为换行符.

最后一种情况是反斜杠,后跟字符串级别的换行符.Java正则表达式语言不会将其识别为特定(正则表达式)转义序列.但是在正则表达式语言中,反斜杠后跟任何非字母字符意味着后一个字符.因此,反斜杠后跟换行符......意味着与换行符相同.

  • 最后的解释我会给你+5.我知道"\n"和"\\n",但不是"\\\n" (2认同)

sp0*_*00m 5

1)假设您要\使用Java的replaceAll方法替换一个:

   \
   ?--- 1) the final backslash
Run Code Online (Sandbox Code Playgroud)

2)Java的replaceAll方法将正则表达式作为第一个参数。在正则表达式文字中\具有特殊含义,例如,\d其中是[0-9](任何数字)的快捷方式。在正则表达式文字中转义元字符的方法是在其前面加上\,导致:

 \ \
 | ?--- 1) the final backslash
 |
 ?----- 2) the backslash needed to escape 1) in a regex literal
Run Code Online (Sandbox Code Playgroud)

3)在Java中,没有regex文字:您可以使用字符串文字编写regex (例如,与JavaScript不同,您可以在其中编写/\d+/)。但是在字符串文字中\也具有特殊含义,例如在\n(换行)或\t(制表符)中。在字符串文字中转义元字符的方法是在其前面加上\,导致:

\\\\
|||?--- 1) the final backslash
||?---- 3) the backslash needed to escape 1) in a string literal
|?----- 2) the backslash needed to escape 1) in a regex literal
?------ 3) the backslash needed to escape 2) in a string literal
Run Code Online (Sandbox Code Playgroud)