对于正则表达式,如果两个模式都是贪心的,那么模式引擎实际上是如何选择匹配的呢?
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"
,"1540
和1540 "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"
.
昨天,我和室友讨论了一个关于栈的问题。这个问题在这里
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"
,"1540
和1540 "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"
.