$s = "bla..bla";
$s =~ s/([^%])\./$1/g;
我认为它应该用.
之前的字符替换所有不在%
之后的.
。
但是$s
是:bla.bla
,但是
它应该是blabla
。问题出在哪儿?我知道我可以使用量词,但我需要这样做。
答案 0 :(得分:9)
当全局正则表达式搜索字符串时,它将找不到重叠匹配。
字符串中的第一个匹配项为a.
,后面会替换为a
。当正则表达式引擎恢复搜索时,它会从下一个.
开始,因此它会将.bla
视为字符串的其余部分,并且您的正则表达式需要在.
之前匹配一个字符,因此它无法匹配试。
相反,使用负面的lookbehind来执行前一个字符不是%
的断言:
$s =~ s/(?<!%)\.//g;
请注意,如果您使用(?<=[^%])
之类的正面后瞻,如果它是字符串中的第一个字符,则不会替换.
。
答案 1 :(得分:6)
问题是即使使用/g
标志,每次替换都会开始查看前一个替换的位置。您尝试将a.
替换为a
,然后将a.
替换为a
,但第二次替换不会发生,因为a
已经“被以前的替换吞下了。
一种解决方法是使用zero-width lookbehind assertion:
$s =~ s/(?<=[^%])\.//g;
将删除不字符串中的第一个字符的任何.
,并且 not 前面有%
。
但你可能真的想要这个:
$s =~ s/(?<!%)\.//g;
将删除{em>之前 的.
,即使 是字符串中的第一个字符。
答案 2 :(得分:3)
比后视更简单的是使用:
$s =~ s/([^%])\.+/$1/g;
这将替换除%
以外的字符后的任何一个或多个点的任何字符串。