用于“AND NOT”操作的正则表达式

时间:2011-09-25 21:36:39

标签: regex logical-operators

我正在寻找一个通用的正则表达式构造来匹配模式中的所有内容x EXCEPT匹配模式y。这很难完整和简洁地解释......请参阅Material Nonimplication以获得正式定义。

例如,匹配任何单词字符(\w)除了'p'。注意我从一个较大的集合(所有单词字符)中减去一个小集合(字母'p')。我不能只说[^p],因为这并没有考虑到只有单词字符的更大限制集。对于这个小例子,当然,我可以手动重建像[a-oq-zA-OQ-Z0-9_]这样的东西,这是一个痛苦但可行的。但我正在寻找一个更通用的结构,以便至少大的正集可以是一个更复杂的表达式。与匹配((?<=(so|me|^))big(com?pl{1,3}ex([pA]t{2}ern)类似,除非它以“我的”开头。

编辑:我意识到这是一个不好的例子,因为在开始或结束时排除内容是负面前瞻和后视表达式工作的情况。 (波希米亚人,我仍然给你一个赞成说明这一点)。那么......在中间的某个地方排除包含“我的”的匹配怎么样?...我仍然在寻找一个通用的构造,比如下面的伪sql的正则表达式

select [captures] from [input]
where (
    input MATCHES [pattern1]
    AND NOT capture MATCHES [pattern2]
)

如果答案是“它不存在,这就是为什么......”我也想知道。

编辑2 :如果我想定义自己的函数来执行此操作,那就像(这里是C#LINQ版本):

public static Match[] RegexMNI(string input, 
                               string positivePattern, 
                               string negativePattern) {
    return (from Match m in Regex.Matches(input, positivePattern)
            where !Regex.IsMatch(m.Value, negativePattern)
            select m).ToArray();
}

我仍然只是想知道是否有可以做到这一点的本地正则表达式构造。

4 个答案:

答案 0 :(得分:19)

这将匹配 一个单词并且 a p的任何字符:

((?=[^p])\w)

要解决您的示例,请在输入中的任意位置使用“我的”的否定预测,即(?!.*My)

^(?!.*My)((?<=(so|me|^))big(com?pl{1,3}ex([pA]t{2}ern)

请注意启动输入^的锚点,这是使其工作所必需的。

答案 1 :(得分:15)

我想知道为什么人们会尝试用大型的整体正则表达式做复杂的事情?

为什么不能将问题分解为子部分,然后制作非常简单的正则表达式来单独匹配?在这种情况下,首先匹配\w,然后匹配[^p],如果第一次匹配成功。 Perl(和其他语言)允许构建看起来非常复杂的正则表达式,这些正则表达式允许您在一个大的blobby-regex中完成您需要做的事情(或者,它可能是一个简短而快速的加密正则表达式) ,但是为了那些需要阅读(并维护!)代码的人,你需要完全记录它。最好是从一开始就让它易于理解。

抱歉,咆哮。

答案 2 :(得分:5)

编辑完成后,它仍然是负面预测,但还有一个额外的量词。

如果你想确保整个字符串不包含“我的”,那么你可以这样做

(?!.*My)^.*$

here on Regexr

这将匹配任何字符序列(末尾为.*),并且当字符串中的任何位置有“我的”时,开头的(?!.*My).*将失败。

如果你想匹配任何不完全“我的”的东西,那么使用锚点

(?!^My$).*

答案 3 :(得分:1)

因此,在查看RegEx的这些主题后:lookahead,lookbehind,nesting,AND运算符,递归,子程序,条件,锚点和组,我得出的结论是没有解决方案满足你的要求。

前瞻不起作用的原因是因为它在这个相对简单的情况下失败了:

  

没有My的三个单词作为一个单词。

正则表达式:

  

^(?!。* My。*)(\ b \ w + \ b \ s \ b \ w + \ b \ s \ b \ w + \ b)

匹配

  

作为一个

包含在内

前三个单词无法匹配,因为我发生在他们之后。如果“我的”位于整个字符串的末尾,那么你永远不会匹配任何东西,因为每个前瞻都会失败,因为他们都会看到它。

问题似乎是,虽然前瞻有一个关于它开始匹配的位置的隐式锚,但是根据RegEx的另一部分的结果,没有办法终止前瞻结束其搜索的锚点。这意味着您必须将所有RegEx复制到负向前瞻中,以手动创建您所追求的锚点。

令人沮丧和痛苦。 “解决方案”似乎是使用脚本语言来执行两个正则表达式。一个在另一个之上。我很惊讶这种功能并没有更好地构建到正则表达式引擎中。