为什么用绳子。java中的replaceAll()需要正则表达式中的4个斜杠“\\\\”来实际替换“\”?
我最近注意到,字符串。replaceAll(regex,replacement)在转义字符“\”(斜杠)上的行为非常奇怪
例如,考虑有一个带有FielPATH的字符串^ {< CD1>}
我们想用"/"
替换"\\"
text.replace("\\","/")
给出输出"E:/dummypath"
,而text.replaceAll("\\","/")
引发异常java.util.regex.PatternSyntaxException
如果我们想用replaceAll()
实现相同的功能,我们需要将其编写为,
text.replaceAll("\\\\","/")
一个显著的区别是replaceAll()
的参数是regex,而replace()
的参数是字符序列
但是text.replaceAll("\n","/")
的工作原理与其对应的字符序列text.replace("\n","/")
完全相同
挖得更深: 当我们尝试其他输入时,甚至可以观察到更奇怪的行为
让我们分配text="Hello\nWorld\n"
现在,,
text.replaceAll("\n","/")
,text.replaceAll("\\n","/")
,text.replaceAll("\\\n","/")
所有这三个都给出相同的输出Hello/World/
Java真的以我感觉最好的方式把reg-ex搞砸了!在reg-ex中,似乎没有其他语言具有这些好玩的行为。有什么具体原因吗,为什么Java会这样一团糟
# 1 楼答案
您需要esacpe两次,一次用于Java,一次用于正则表达式
Java代码是
生成一个正则表达式字符串
但是regex也需要一种逃避,所以它变成了
# 2 楼答案
这是因为Java试图在替换字符串中赋予
\
一个特殊含义,因此\$将是一个字面的$符号,但在这个过程中,它们似乎删除了\
的实际特殊含义虽然
text.replaceAll("\\\\","/")
,至少在某种意义上可以被认为是好的(尽管它本身并不是绝对正确的),但所有三次执行,text.replaceAll("\n","/")
,text.replaceAll("\\n","/")
,text.replaceAll("\\\n","/")
给出相同的输出似乎更有趣。为什么他们出于同样的原因限制了text.replaceAll("\\","/")
的功能,这恰恰是自相矛盾的Java没有搞乱正则表达式。这是因为,Java喜欢在完全不需要的情况下,通过尝试做一些独特和不同的事情来搞乱程序员
# 3 楼答案
1)假设您想使用Java的
replaceAll
方法替换单个\
:2)Java的,这会导致:
replaceAll
方法将正则表达式作为第一个参数。在regex literal中,\
具有特殊含义,例如在\d
中,它是[0-9]
(任何数字)的快捷方式。在regex literal中转义元字符的方法是在它前面加一个^{3)在Java中,没有正则表达式literal:您可以在字符串literal中编写正则表达式(例如,与JavaScript不同,在JavaScript中您可以编写^{)。但是在字符串literal中,,这会导致:
\
也有特殊含义,例如在\n
(新行)或\t
(制表符)中。在字符串literal中转义元字符的方法是在其前面加一个^{# 4 楼答案
我认为java真的弄乱了字符串中的正则表达式。replaceAll()
除了java,我从未见过一种语言以这种方式解析正则表达式。如果你在其他语言中使用过正则表达式,你会感到困惑
在替换字符串中使用
"\\"
的情况下,可以使用java.util.regex.Matcher.quoteReplacement(String)
通过使用这个
Matcher
类,您可以得到预期的结果# 5 楼答案
@Peter Lawrey的回答描述了这些机制。“问题”在于反斜杠在Java字符串文本和小型正则表达式语言中都是转义字符。因此,当使用字符串文字表示正则表达式时,有两组需要考虑的逸出…取决于你想要正则表达式的意思
但为什么会这样
这是一个历史事件。Java最初根本没有正则表达式。java字符串文字的语法规则是从C/C++中借用的,它也没有内置的正则表达式支持。双重转义的尴尬在Java中并不明显,直到他们以
Pattern
类的形式添加了正则表达式支持。。。在Java1.4中那么其他语言如何避免这种情况呢
它们通过在编程语言本身中为正则表达式提供直接或间接的语法支持来实现。例如,在Perl、Ruby、Javascript和许多其他语言中,patterns/regexs(例如,“/pattern/”)的语法不适用字符串文字转义规则。在C#和Python中,它们提供了另一种“原始”字符串文字语法,其中反斜杠不是转义符。(但请注意,如果使用普通的C#/Python字符串语法,就会遇到Java的双重转义问题。)
第一种情况是字符串级别的换行符。Java正则表达式语言将所有非特殊字符视为自身匹配
第二种情况是字符串级别的反斜杠后跟“n”。Java正则表达式语言将后跟“n”的反斜杠解释为换行符
最后一个大小写是反斜杠,后跟字符串级别的换行符。Java正则表达式语言不将其视为特定的(正则表达式)转义序列。然而,在正则表达式语言中,反斜杠后跟任何非字母字符表示后一个字符。所以,一个反斜杠后跟一个换行符。。。意思和新线一样
# 6 楼答案
解决此问题的一种方法是用另一个字符替换反斜杠,使用该替代字符进行中间替换,然后在结尾将其转换回反斜杠。例如,要将“\r\n”转换为“\n”:
当然,如果选择一个可能出现在输入字符串中的替换字符,这将不会很好地工作