可变宽度负向外观中的Star vs. plus量词
愚蠢的问题在这里…我试图匹配线内的空白区域而忽略前导空格/标签并提出这些正则表达式字符串,但我无法弄清楚为什么只有一个工作(C#正则表达式引擎) :
(?<!^[ \t]*)[ \t]+ // regex 1. (with *) (?<!^[ \t]+)[ \t]+ // regex 2. (with +)
请注意负面预测中的明星与加重复。 将这些与" word1 word2"
(2个前导空格)匹配时:
⎵⎵word1⎵word2 ^ // 1 match for regex 1. (*) ⎵⎵word1⎵word2 ^^ ^ // 2 matches for regex 2. (+) ^ ^ // why not match like this?
为什么只有版本1.(星号)在这里工作而版本2.(加号)与第二个领先空间不匹配?
我认为这是因为贪婪的优先级+
来自[ \t]+
不是前瞻,但我怎么能理性化呢?
简而言之 :
负面的lookbehind仅检查当前位置是否前面有lookbehind模式,并且检查结果为true (是,继续匹配)或false (停止处理模式,转到下一个匹配)。 检查不影响正则表达式索引,执行检查后引擎保持在同一位置。
在当前表达式中, 首先检查lookbehind模式(因为模式从左到右解析,反之亦然),并且只有当lookbehind检查返回true时才尝试[ \t]+
模式。 在第一个表达式中, 负向lookbehind返回false,因为lookbehind模式找到匹配(字符串的开头)。 第二个表达式负向lookbehind返回true,因为没有字符串的开头,后面跟着一个字符串开头的一个或多个空格/制表符。
以下是2个表达式背后的逻辑:
-
首先执行lookbehind检查。 在第一个表达式中,
(?尝试在字符串的开头匹配。 字符串的开头没有字符串的开头(
^
),后跟0 +空格或制表符。 重要的是要注意.NET中的lookbehind实现检查相反方向的字符串,翻转字符串,并搜索零个或多个选项卡和字符串边界。 在(? ,lookbehind返回false,因为在0个空格或制表符之前有一个起始位置(注意我们仍然在字符串的开头)。 第二个表达式lookbehind,
(? ,返回true,因为在字符串的第0个索引处的字符串开头之前没有制表符或空格,因此,
[ \t]+
消耗模式抓住领先的水平空白。 这会进一步移动正则表达式索引,并且稍后会在字符串中找到另一个匹配项。 -
在字符串开头失败后,第一个表达式尝试在第一个空格后匹配。 但是,
(?返回false,因为有一个字符串后跟1个空格(第一个)。 同样的故事在第二个空间之后重复。 与第一个
(?表达式匹配的唯一空格是那些不在字符串开头的空格。
Lookahead比喻
检查类似的先行模式: [ \t]+(?![ \t]+$)
模式将在"bb bb "
找到两个空白块,而[ \t]+(?![ \t]*$)
将不匹配字符串末尾的那些。 相同的逻辑适用:1) *
版本允许匹配空字符串,因此找到字符串的结尾并且否定前瞻返回false,匹配失败。 当+
版本遇到并使用尾随空格时,停留在字符串末尾的正则表达式引擎找不到一个或多个空格/制表符后跟另一个字符串结尾,因此,负向前导返回true并且尾随空格匹配。