5
$s = "bla..bla";
$s =~ s/([^%])\./$1/g;

我认为它应该将所有出现的.that is not after%替换为 before 的字符.

But $sis then: bla.bla, 但它应该是blabla. 问题出在哪里?我知道我可以使用量词,但我需要这样做。

4

3 回答 3

11

当全局正则表达式搜索字符串时,它不会找到重叠的匹配项。

字符串中的第一个匹配项将是a.,替换为a。当正则表达式引擎恢复搜索时,它从下一个开始,.所以它看到.bla视为字符串的其余部分,并且您的正则表达式需要一个字符在之前匹配,.因此它不能再次匹配。

相反,使用否定的lookbehind来执行前一个字符不是的断言%

$s =~ s/(?<!%)\.//g;

请注意,如果您使用积极的后视,如果它是字符串中的第一个字符(?<=[^%]),您将不会替换它。.

于 2013-02-20T17:21:59.557 回答
6

问题是即使有了/g标志,每次替换都会开始查找前一个替换的位置。您尝试替换a.a,然后a.替换为a,但第二次替换没有发生,因为a已经被前一次替换“吞下”。

一种解决方法是使用零宽度后向断言

$s =~ s/(?<=[^%])\.//g;

这将删除任何.不是字符串第一个字符且前面没有.%

但你可能真的想要这个:

$s =~ s/(?<!%)\.//g;

即使它字符串中的第一个字符,它将删除任何.以开头的字符。%

于 2013-02-20T17:21:59.400 回答
3

比look-behinds简单得多的是使用:

$s =~ s/([^%])\.+/$1/g;

这将替换字符后的任何一个或多个点的字符串,而不是%什么都没有。

于 2013-02-20T17:26:58.960 回答