Java正则表达式中[\s\S]*?和.*?有什么区别?

14

我已经开发了一个正则表达式来识别文本文件中的XML块。该表达式如下(为了易读,我删除了所有Java转义斜杠):

<\?xml\s+version="[\d\.]+"\s*\?>\s*<\s*rdf:RDF[^>]*>[\s\S]*?<\s*\/\s*rdf:RDF\s*>

然后我进行了优化,并将[\s\S]*?替换为.*?,结果它突然无法识别xml。

据我所知,\s表示所有的空格符号,\S表示所有的非空格符号或[^\s],因此[\s\S]在逻辑上应该等同于.。我没有使用贪婪模式,那么可能有什么区别呢?


3
默认情况下,. 不会匹配换行符。如果使用 Pattern.DOTALL 标志,它可能匹配所有字符(包括换行符)。设置了 [\s\S],其中包括所有空格 \s 和所有非空格 \S,有效地代表所有字符(包括换行符)。 - Pshemo
在这两种情况下,尾随的问号都没有任何作用。 - user207421
一个非常相关的问题:这些正则表达式有什么区别 - Wiktor Stribiżew
太棒了,这个问题真让我惊讶,竟然没有更多的赞同。 - setholopolus
3个回答

19

正则表达式中的.\s\S并不等价,因为.默认情况下不匹配行终止符(如换行符)。

根据Oracle网站所述,.匹配:

任何字符(可以是行终止符也可以不是)

而行终止符包括以下内容:

  • 换行符(LF字符)('\n'
  • 紧随其后的回车符和换行符(CRLF序列)("\r\n"
  • 独立的回车符(CR字符)('\r'
  • 下一行字符(NEL字符)('\u0085'
  • 行分隔符(LS字符)('\u2028'
  • 段分隔符(PS字符)('\u2029'

这两个表达式在没有设置必要标志的情况下是不等价的。再次引用Oracle网站:

如果激活了UNIX_LINES模式,则唯一被识别的行终止符是换行符。
正则表达式.匹配除行终止符以外的任何字符,除非指定了DOTALL标志。

4

这里有一份说明所有正则表达式命令的文档。

基本上,\s\S会匹配所有字符,包括换行符。而.不会默认匹配行尾标记(需要设置特定标志才能匹配)。


是的,每个 \ 都已经被双重转义了。我已经删除了双斜杠,只是为了方便阅读。这个表达式是有效的,但是一旦我用 .*? 替换了 [\s\S]*?,它就停止工作了,所以差异应该在那里。 - Dmitry
这是真实表达式:<\\?xml\\s+version=\"[\\d\\.]+\"\\s*\\?>\\s*<\\s*rdf:RDF[^>]*>[\\s\\S]*?<\\s*\\/\\s*rdf:RDF\\s*> - Dmitry
这不是真的。 . 可以根据某些标志转义换行符。请查看我的答案获取所有详细信息。 - Neuron
1
@Neuron 我引用的来源指出 . 不能捕获换行符。这就是我所依据的。现在我意识到它可能没有我想象的那么可信。 - z7r1k3

0

就像在JavaScript中一样,尽管我不习惯Java,但Java是一种程序类型,在我们的现实生活中非常有用。


1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接