为啥这个正则表达式匹配?

Posted

技术标签:

【中文标题】为啥这个正则表达式匹配?【英文标题】:Why is this regex matching?为什么这个正则表达式匹配? 【发布时间】:2018-08-24 17:55:21 【问题描述】:

下午好!我试图编写一个仅当字符串包含给定格式的日期或两个匹配短语之一时才匹配的模式:

(?=(?<p0>(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ ](\d+)(,)[ ](\d+)[ ](\d+):(\d+):(\d+) (PM|AM)))?(?=(?<p1>MATCHINGPHRASE2))?(?=(?<p2>MATCHINGPHRASE3))?

我有一个方法调用使用这种模式的正则表达式,如下所示:

internal bool IsSubjectRecognized(string subject)
    
        var match = _regEx.Match(subject);
        if (match.Success)
        
            return true;
        
        return false;
    

最后,我有一个单元测试,以确保上述方法对于不包含日期的字符串返回 false,或者匹配如下所示的短语:

public void IsSubjectRecognizedRejectsReggoStrings()
    
        var subject = "Watch out for the medalions. My diamonds are wreckless.";
        var rules = new MatchingRules();
        Assert.IsFalse(rules.IsSubjectRecognized(subject));
    

为什么返回 true?!

【问题讨论】:

假设 实际上不是模式的一部分,正则表达式模式中的所有内容都是可选的(后跟 ?),因此模式匹配每个字符串。 如果您在破译/理解您的正则表达式时遇到困难,您可以借助 debuggex.com 之类的服务将其逻辑可视化(确保选择 PCRE 作为正则表达式风格) @elgonzo 整洁!谢谢大佬! 模式中的所有主要组都使用? 进行量化,因此它将匹配字符串开头、字符串结尾以及每个字符之间的零长度位置。 【参考方案1】:

让我们像使用 perl 的 /x 修饰符一样解开该正则表达式(我已将空格转换为 \x20,因为 /x 跳过了空格和 cmets):

(?=
  (?<p0>
    (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
    [\x20]
    (\d+)
    (,)
    [\x20]
    (\d+)
    [\x20]
    (\d+):(\d+):(\d+)\x20(PM|AM)
  )
)?
(?=
  (?<p1>MATCHINGPHRASE2)
)?
(?=
  (?<p2>MATCHINGPHRASE3)
)?

让我们简化一下,看看外层发生了什么:

(?= (?<p0>DATEREGEX) )?
(?= (?<p1>MATCHINGPHRASE2) )?
(?= (?<p2>MATCHINGPHRASE3) )?

这会创建三个可选零宽度前瞻,因此它应该匹配任何内容。

考虑(使用 perl,因为它很容易在命令行上演示):

$ echo foo |perl -ne 'print if /(?=nope)?/'
foo

如果foo(?=nope)? 匹配,则应该打印它。打印出来了,所以有匹配项。

前瞻通常用于向前跳过以确保存在某些内容。我不认为您希望在这里这样做,但是如果没有一些应该和不应该匹配的示例文本,我无法确定。

你可能只想要这样的东西:

(?<p0>
  (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
  [\x20]
  (\d+)
  (,)
  [\x20]
  (\d+)
  [\x20]
  (\d+):(\d+):(\d+)\x20(PM|AM)
)
(?<p1>MATCHINGPHRASE2)
(?<p2>MATCHINGPHRASE3)

或者,又全部崩溃了:

(?<p0>(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d+)(,) (\d+) (\d+):(\d+):(\d+)\x20(PM|AM))(?<p1>MATCHINGPHRASE2)(?<p2>MATCHINGPHRASE3)

(您也不需要这些字符类;(以及\x20[\x20])与[ ] 相同,除非存在粘贴问题并且我在该类中缺少某些内容。相反,您可能需要\s[[:space:]],这样您就可以覆盖所有空白字符,但我会留给您。)

另见:

Regex101 explanation of your original regex Regex101 explanation of my proposed regex

【讨论】:

以上是关于为啥这个正则表达式匹配?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个正则表达式不生成匹配?

为啥这个正则表达式模式不匹配? [复制]

为啥这个正则表达式需要一个捕获组来匹配?

为啥这个正则表达式只在 Python 中的行首匹配? [复制]

为啥这个重复的内部组在正则表达式中不匹配? [复制]

Qt正则表达式 如何得到字符串中所有满足条件的字符。这个正则为啥匹配不成功