正则表达式元字符“*”和“*?”在 JAVA 的 replaceAll() 方法中行为异常[重复]
Posted
技术标签:
【中文标题】正则表达式元字符“*”和“*?”在 JAVA 的 replaceAll() 方法中行为异常[重复]【英文标题】:Regexp metachars "*" and "*?" in the JAVA's replaceAll() method behave oddly [duplicate] 【发布时间】:2013-01-19 10:50:29 【问题描述】:可能重复:String.replaceAll() anomaly with greedy quantifiers in regexStrange behavior in regexes
虽然
"a".replaceAll("a", "b")
"a".replaceAll("a+", "b")
"a".replaceAll("a+?", "b")
全部返回b
,为什么呢
"a".replaceAll("a*", "b")
返回bb
和
"a".replaceAll("a*?", "b")
返回bab
?
【问题讨论】:
仍在寻找副本... 给你:***.com/questions/9228509/strange-behavior-in-regexes 我认为 Perl 在第二种情况下返回 bbb 。这更有意义。一种*?不匹配“a”很奇怪。 @jdb 我认为我发布的链接很好地解释了这一点。 回显一个 | perl -i -pe "s/a*?/b/g" 【参考方案1】:在"a".replaceAll("a*", "b")
* - 0 或更多,所以在 `a*` 中
1. a - replaced by b
2. * - is also true as empty string is true for *,so, replaced by b
在"a".replaceAll("a*?", "b")
1. *? - makes anything non-greedy means it makes regrex to match as little
as possible,
2. so,the pre and post empty string would be replaced by "b" and
as a*? is non-greedy, it will not replace it
【讨论】:
【参考方案2】:这是因为零宽度匹配。
"a".replaceAll("a*", "b")
将匹配两次:
-
在字符串的开头尝试匹配,贪婪的
*
消耗a
作为匹配。
前进到字符串中的下一个位置(现在在字符串的末尾),尝试在那里匹配,空字符串匹配。
" a "
\| \___ 2. match empty string
\_____ 1. match "a"
"a".replaceAll("a*?", "b")
也会匹配两次:
-
尝试在字符串开头匹配,非贪心
*?
匹配空字符串而不消耗a
。
前进到字符串中的下一个位置(现在在字符串的末尾),尝试在那里匹配,空字符串匹配。
" a "
\ \___ 2. match empty string
\_____ 1. match empty string
【讨论】:
我喜欢这些图表;-)
【参考方案3】:
"a".replaceAll("a*", "b")
首先将a
替换为b
,然后将指针移过b
。然后它匹配字符串的结尾,并替换为b
。因为它匹配一个空字符串,所以它推进指针,从字符串中掉出来,然后结束,产生bb
。
"a".replaceAll("a*?", "b")
首先匹配字符串的开头并替换为b
。它与a
不匹配,因为a*?
中的?
表示“非贪婪”(尽可能少匹配)。由于它匹配一个空字符串,它推进指针,跳过a
。然后它匹配字符串的结尾,替换为b
并从字符串中掉出来,导致bab
。最终结果与您执行"a".replaceAll("", "b")
时相同。
【讨论】:
@mikeslattery 如果指针没有前进,那么只要你匹配一个空字符串,替换器就会陷入无限循环。 打印 bbb。对我来说似乎更合乎逻辑:echo a | perl -i -pe "s/a*?/b/g" @jdb perl 中的规则是什么?如果匹配为空,则指针不会移动,但下一个匹配被限制为非空,通常的规则是先回溯最后一组? 前进到下一个字符,因为空格是匹配的,但不能说明问题。我不知道 Perl 规则是什么,但它更有意义。 Python 也有同样的错误。 @jdb 我不会称之为错误。这确实有道理,而且绝对是故意的。 javascript 的行为与 Java 相同(跳过一个字符)。以上是关于正则表达式元字符“*”和“*?”在 JAVA 的 replaceAll() 方法中行为异常[重复]的主要内容,如果未能解决你的问题,请参考以下文章
java正则表达式,要求字符串只能包含数字、英文大小写、以及“-”符号