我正在寻找一个通用的正则表达式构造来匹配模式中的所有内容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();
}
我仍然只是想知道是否有可以做到这一点的本地正则表达式构造。
答案 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)^.*$
这将匹配任何字符序列(末尾为.*
),并且当字符串中的任何位置有“我的”时,开头的(?!.*My).*
将失败。
如果你想匹配任何不完全“我的”的东西,那么使用锚点
(?!^My$).*
答案 3 :(得分:1)
因此,在查看RegEx的这些主题后:lookahead,lookbehind,nesting,AND运算符,递归,子程序,条件,锚点和组,我得出的结论是没有解决方案满足你的要求。
前瞻不起作用的原因是因为它在这个相对简单的情况下失败了:
没有My的三个单词作为一个单词。
正则表达式:
^(?!。* My。*)(\ b \ w + \ b \ s \ b \ w + \ b \ s \ b \ w + \ b)
匹配
作为一个
包含在内
前三个单词无法匹配,因为我发生在他们之后。如果“我的”位于整个字符串的末尾,那么你永远不会匹配任何东西,因为每个前瞻都会失败,因为他们都会看到它。
问题似乎是,虽然前瞻有一个关于它开始匹配的位置的隐式锚,但是根据RegEx的另一部分的结果,没有办法终止前瞻结束其搜索的锚点。这意味着您必须将所有RegEx复制到负向前瞻中,以手动创建您所追求的锚点。
令人沮丧和痛苦。 “解决方案”似乎是使用脚本语言来执行两个正则表达式。一个在另一个之上。我很惊讶这种功能并没有更好地构建到正则表达式引擎中。