可变宽度负向后视中的Star vs. plus量词

时间:2016-11-09 17:29:35

标签: c# regex negative-lookahead

愚蠢的问题在这里......我试图匹配线内的空白区域,而忽略前导空格/标签并提出这些正则表达式字符串,但我可以&#39 ;弄清楚为什么只有一个工作(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]+优先于预测,但我怎样才能理性化呢?< / p>

1 个答案:

答案 0 :(得分:2)

简而言之

负面的背后检查只是检查当前位置是否前面没有lookbehind模式,并且检查结果是 true (是的,继续匹配)或 false (停止处理模式,进行下一场比赛)。检查不影响正则表达式索引,执行检查后引擎保持在同一位置。

在当前表达式中,首先检查外观模式 (因为模式从从左到右解析,反之亦然),并且仅在后备检查时返回true,尝试[ \t]+模式。在第一个表达式中,否定 lookbehind返回 false ,因为lookbehind模式找到匹配项(字符串的开头)。第二个表达式否定 lookbehind返回 true ,因为字符串的开头没有字符串的开头,后面跟着一个或多个空格/制表符。

以下是两个表达式背后的逻辑:

  • 首先执行lookbehind检查。在第一个表达式中,(?<!^[ \t]*)尝试在字符串的开头匹配。字符串的开头没有字符串的开头(^),后跟0 +空格或制表符。值得注意的是,.NET中的lookbehind实现会以相反的方向检查字符串,翻转字符串,并搜索零个或多个选项卡以及字符串边界。在(?<!^[ \t]*)的情况下,lookbehind返回false,因为在0个空格或制表符之前有一个起始位置(注意我们仍然在字符串的开头)。第二个表达式lookbehind,(?<!^[ \t]+),返回true,因为在字符串的第0个索引处的字符串开头之前没有制表符或空格,因此[ \t]+消费模式抓取前导水平空格。这会进一步移动正则表达式索引,稍后会在字符串中找到另一个匹配。

  • 在字符串开头失败后,第一个表达式尝试在第一个空格后匹配。但是,(?<!^[ \t]*)返回false,因为字符串的开头后跟1个空格(第一个)。同样的故事在第二个空间之后重复。与第一个(?<!^[ \t]*)[ \t]+表达式匹配的唯一空格是那些不在字符串开头的空格。

Lookahead类比

检查类似的前瞻模式:[ \t]+(?![ \t]+$)模式将在"bb bb "中找到两个空白块,而[ \t]+(?![ \t]*$)将与字符串末尾的那些不匹配。同样的逻辑适用:1)*版本允许匹配空字符串,因此找到字符串的结尾而负向前导返回false,匹配失败。当+版本遇到并消耗尾随空格时,停留在字符串末尾的正则表达式引擎找不到一个或多个空格/制表符后跟另一个字符串结尾,因此,否定前瞻返回true并且尾随空格是匹配的。