对于正则表达式,如果两个模式都是贪心的,那么模式引擎实际上是如何选择匹配的呢?

For Regex, if the two pattern are all greedy, how does the pattern engine chose the match practically?

昨天,我和室友讨论了一个关于栈的问题。这个问题在这里

How to get the second column from command output?

他们讨论如何像这样将第二列与输入流分开:

1540 "A B"
   6 "C"
 119 "D"

第一个赞成的答案

<some_command> | sed 's/^.* \(".*"$\)//'

结果完全满足要求。

但后来我们发现如果我们遵循正则表达式的贪婪规则,模式 ^.*␣ 将匹配 1540 "A 这让我的室友感到困惑。事后看来,模式 ^.*␣ 应该与模式 (".*"$) 做出妥协。否则,第二个模式将不匹配任何内容。然而,我的室友无法相信我的假设。所以这个人给我另一个例子来测试,我们确实做到了。

我们做了两个实验。 1st 添加引号 " 跟在字符 A 之后,如下所示:

1540 "A" B"
   6 "C"
 119 "D"

用前面的正则表达式很容易得到这个结果:

"A" B"
"C"
"D"

而对于 2nd 一个,我们在 A 后面添加一个白色 space 和一个引号 ␣",如下所示:

1540 "A " B"
   6 "C"
 119 "D"

结果是:

" B"
"C"
"D"

直到现在,我的室友变得更加困惑,因为他的注意力总是集中在第二个模式上(".*"$)。在他看来,模式 (".*"$) 应该观察到两个字符串 1540 "A" B"1540 "A " B" 之间的相同行为,所以第二个测试的结果应该是 "A " B" 而不是 " B".我认为对于第二个,可以肯定模式 ^.*␣ 无法匹配这部分 1540 "A" 这将导致第二个模式不匹配。但是对于第二个实验1540 "A " B""15401540 "A这两个选择似乎都是合理的,不同的是前者是(".*"$)贪心的结果,后者是由于^.*␣ 的。

所以谁能给我一个更具体的答案来辨别我们困惑的关键。谢谢.

A .* 模式是 greedy 从某种意义上说,它会首先尝试尽可能多地匹配,然后通过字符串回溯,匹配较少和必要时减少。正则表达式是从左到右匹配的,这意味着第一个.*的贪婪将在歧义的情况下支配第二个。

让我们将这个想法应用到 1540 "A" B"

简化后,正则表达式为:

^.* (".*")$
  • 首先,尝试将 整个 字符串与第一个 .* 匹配。
    • 糟了,我们接下来要匹配一个space!
  • 好的,让我们尝试一切,直到最后一个space:1540 "A"
    • 不好。引号 " 必须跟在 space.
    • 之后
  • 好吧,让我们再往回看一点……在这里,1540 之后的 space 后面跟了一个引号。

然后,它将匹配表达式的其余部分并成功。因此,第一个 .* 最贪婪匹配 1540,该组匹配字符串的其余部分 "A" B".

现在让我们将它应用到 1540 "A " B"

  • 首先,尝试将 整个 字符串与第一个 .* 匹配。
    • 糟了,我们接下来要匹配一个space!
  • 好的,让我们尝试一切,直到最后一个space:1540 "A "
    • 不好。引号 " 必须跟在 space.
    • 之后
  • 好吧,让我们再往回看一点……哦,看! 1540 "A 之后的 space 后面是引号!我们可以比上次稍微贪一点。

第一个 .* 最贪婪匹配 现在是 1540 "A,该组将匹配字符串的其余部分 " B" .