使用 lookbehind 时正则表达式引擎内部发生了什么?
What's happening inside regex engine while working with lookbehind?
我正在使用 PHP 和 JavaScript 的正则表达式。所以,我一直在寻找一些好的教程。从这个正则表达式 tutorial 我找到了一个 lookbehind 的例子,它匹配一个特定的 3 位数字,前提是它前面有单词 "USD"。在两种不同的情况下,lookbehind 会在比赛之前和之后进行。
以下是正则表达式模式:
\d{3}(?<=USD\d{3}) //after the match
(?<=USD)\d{3} //before the match
示例字符串为:
USD100;
我明白了这个想法,但无法弄清楚正则表达式引擎内部究竟发生了什么来完成任务。任何人都可以轻松地向我解释一下,以便我理解。提前致谢。
(?<=USD)\d{3}
The lookbehind (?<=USD)
asserts that at the current
position in the string, what precedes is the characters "USD". If the
assertion succeeds, the engine matches three digits with \d{3}
.
\d{3}(?<=USD\d{3})
\d{3}
matches 100, then the lookbehind
(?<=USD\d{3})
asserts that at that position in the string, what
immediately precedes is the characters "USD" then three digits.
你的问题是
Then how both of them gives the same result where one is after the match and other is before the match?
每个示例模式中的环视并不相等。参见
\d{3}(?<=USD\d{3})
^^^^^
(?<=USD)\d{3}
第一个检查字符串中当前位置之前是否有USD
和 3位数字(即after 3位数)
第二个检查字符串中当前位置之前是否只有 USD
(即 3 位数字之前的 )。
这是一个可视化:
\d{3}(?<=USD\d{3}) (?<=USD)\d{3}
and
下面的示例显示了 PCRE(和大多数引擎)如何实现后视。在每种情况下,在进入后视之前记下光标的位置。
在\d{3}(?<=USD\d{3})
的情况下,注意匹配\d{3}
后光标前进了3个位置,所以look-behind需要看过去的3位消费是为了在他们面前检查美元。
此方法确保数字先出现,然后再检查前缀。
USD100;
^
Attempting to match \d{3}. Fail and bump along.
USD100;
^
Attempting to match \d{3}. Fail and bump along.
USD100;
^
Attempting to match \d{3}. Fail and bump along.
USD100;
^
Attempting to match \d{3}.
USD100;
^
Matched \d{3}. Attempting to assert (?<=USD\d{3}) (length 6).
USD100;
^ +
Save current position. Go back 6 characters.
(Attempt to match USD\d{3} succeeds, positive look-behind succeeds)
USD100;
^
Back to the saved position and report a match.
在(?<=USD)\d{3}
的情况下,注意光标在100
的正前方,所以只需要回头看3个字符,就可以判断是否有USD .
此方法确保前缀首先存在,然后再匹配数字。
USD100;
^
Attempting to assert (?<=USD) (length 3). Fail length check and bump along.
USD100;
^
Attempting to assert (?<=USD) (length 3). Fail length check and bump along.
USD100;
^
Attempting to assert (?<=USD) (length 3). Fail length check and bump along.
USD100;
^
Attempting to assert (?<=USD) (length 3).
USD100;
^ +
Save current position. Go back 3 characters.
(Attempt to match USD succeeds, positive look-behind succeeds)
USD100;
^
Back to the saved position. Attempting to match \d{3}.
USD100;
^
Matched \d{3} and report a match.
look-behind 不是一个明确定义的操作,因此不同的引擎对 look-behind 中允许的操作有不同的实现和限制。
.NET 通过 matching the pattern inside look-behind from right-to-left 实现后视。这使得将任何构造放入后视成为可能,但由于模式中的标记是从右到左读取的,因此当模式包含反向引用时会造成混淆。
其他引擎(包括PCRE)选择从左到右匹配look-behind里面的pattern,通过学习pattern来确定pattern的长度,从当前位置减去模式的长度。由于并非所有模式都有长度限制,因此大多数引擎会拒绝此类模式以保持合理的性能。
我正在使用 PHP 和 JavaScript 的正则表达式。所以,我一直在寻找一些好的教程。从这个正则表达式 tutorial 我找到了一个 lookbehind 的例子,它匹配一个特定的 3 位数字,前提是它前面有单词 "USD"。在两种不同的情况下,lookbehind 会在比赛之前和之后进行。
以下是正则表达式模式:
\d{3}(?<=USD\d{3}) //after the match
(?<=USD)\d{3} //before the match
示例字符串为:
USD100;
我明白了这个想法,但无法弄清楚正则表达式引擎内部究竟发生了什么来完成任务。任何人都可以轻松地向我解释一下,以便我理解。提前致谢。
(?<=USD)\d{3}
The lookbehind(?<=USD)
asserts that at the current position in the string, what precedes is the characters "USD". If the assertion succeeds, the engine matches three digits with\d{3}
.
\d{3}(?<=USD\d{3})
\d{3}
matches 100, then the lookbehind(?<=USD\d{3})
asserts that at that position in the string, what immediately precedes is the characters "USD" then three digits.
你的问题是
Then how both of them gives the same result where one is after the match and other is before the match?
每个示例模式中的环视并不相等。参见
\d{3}(?<=USD\d{3})
^^^^^
(?<=USD)\d{3}
第一个检查字符串中当前位置之前是否有USD
和 3位数字(即after 3位数)
第二个检查字符串中当前位置之前是否只有 USD
(即 3 位数字之前的 )。
这是一个可视化:
\d{3}(?<=USD\d{3}) (?<=USD)\d{3}
and
下面的示例显示了 PCRE(和大多数引擎)如何实现后视。在每种情况下,在进入后视之前记下光标的位置。
在
\d{3}(?<=USD\d{3})
的情况下,注意匹配\d{3}
后光标前进了3个位置,所以look-behind需要看过去的3位消费是为了在他们面前检查美元。此方法确保数字先出现,然后再检查前缀。
USD100; ^ Attempting to match \d{3}. Fail and bump along. USD100; ^ Attempting to match \d{3}. Fail and bump along. USD100; ^ Attempting to match \d{3}. Fail and bump along. USD100; ^ Attempting to match \d{3}. USD100; ^ Matched \d{3}. Attempting to assert (?<=USD\d{3}) (length 6). USD100; ^ + Save current position. Go back 6 characters. (Attempt to match USD\d{3} succeeds, positive look-behind succeeds) USD100; ^ Back to the saved position and report a match.
在
(?<=USD)\d{3}
的情况下,注意光标在100
的正前方,所以只需要回头看3个字符,就可以判断是否有USD .此方法确保前缀首先存在,然后再匹配数字。
USD100; ^ Attempting to assert (?<=USD) (length 3). Fail length check and bump along. USD100; ^ Attempting to assert (?<=USD) (length 3). Fail length check and bump along. USD100; ^ Attempting to assert (?<=USD) (length 3). Fail length check and bump along. USD100; ^ Attempting to assert (?<=USD) (length 3). USD100; ^ + Save current position. Go back 3 characters. (Attempt to match USD succeeds, positive look-behind succeeds) USD100; ^ Back to the saved position. Attempting to match \d{3}. USD100; ^ Matched \d{3} and report a match.
look-behind 不是一个明确定义的操作,因此不同的引擎对 look-behind 中允许的操作有不同的实现和限制。
.NET 通过 matching the pattern inside look-behind from right-to-left 实现后视。这使得将任何构造放入后视成为可能,但由于模式中的标记是从右到左读取的,因此当模式包含反向引用时会造成混淆。
其他引擎(包括PCRE)选择从左到右匹配look-behind里面的pattern,通过学习pattern来确定pattern的长度,从当前位置减去模式的长度。由于并非所有模式都有长度限制,因此大多数引擎会拒绝此类模式以保持合理的性能。