/.*/整个字符串之后的第二个匹配是什么?

时间:2019-07-08 02:26:26

标签: regex ruby

我在 Ruby 中得到了正则表达式。

首先,问题本身并不相同。 这不是一个相同的问题,因为答案是不同的。 而且评论中的讨论也有所不同。

在第一个结果中,匹配整个.*后,看起来'hello'匹配没有

但是为什么会发生呢?

[53] pry(main)> "hello".gsub(/.*/, "abc")
=> "abcabc"
[54] pry(main)> "hello".gsub(/^.*$/, "abc")
=> "abc"

2 个答案:

答案 0 :(得分:4)

重要的一点是,regexp在同一位置永远不能匹配两次。比赛也不能重叠。此外,请注意,"hello"中涉及六个可能的位置:一个在每个字符的开头,一个在末尾(请参见fenceposting)。

当您开始搜索/.*/时,位置0处存在一个匹配项,并且该匹配项占用五个字符。这会使排名0、1、2、3和4的比赛失去资格(因为它们是第一场比赛的一部分)。

第二个匹配项从位置5开始匹配,并找到“ 0个或更多字符”(即0个字符)的匹配项。排名5不在第一场比赛中,因此也没有被“不重叠”规则取消资格。


当您以/^.*/定位起点时,位置5不符合条件,因为它不是起点。

当您用/.*$/定位末尾时,位置0和位置5都会检测到它们的5个字符或0个字符匹配之后,它们分别位于搜索字符串的末尾,因此您仍然可以都匹配。

当您使用/.+/将正则表达式更改为“ 1个或更多字符”时,位置5再次不符合条件,因为没有更多的字符可匹配,但至少需要1个字符。


还请注意,不仅仅是Ruby,在我测试的所有引擎中都发现了相同的行为。 Python的sub有点不一致(可能是因为其邻接条件?不确定),但是findall报告了两个相同的匹配项:

re.findall('.*', 'hello') # => ['hello', '']

JavaScript的工作方式类似于Ruby:

"hello".replace(/.*/g, "abc") // => "abcabc"

Java也是如此:

"hello".replaceAll(".*", "abc") // => "abcabc"

甚至是PHP(使用PREG):

preg_replace('/.*/', 'abc', 'hello'); # => "abcabc"

答案 1 :(得分:1)

这是因为正则表达式引擎不会返回,这意味着当它与某些文本匹配时,它将永远不会在匹配的文本内返回,也就是说,matvhes不会重叠。

您使用了*量词,表示它是贪婪的,因此将尽可能匹配。如果您使用*?,那么您将在字符串的每个位置获得匹配,因为?使它变得非贪婪,因此它将至少匹配。 *表示零个或多个字符,但您将获得0个长度的匹配项。