匹配所有字符,但排除某些词
我这几天在学习正则表达式(Regex),并在用Python实现它,但遇到了一些问题还没解决。
我有一段这样的文本:
FOO1 = BAR2 AND Var1
Gene3 = Gene4 >= 3
Kinase = MATH OR NOT Science
BOOP = 3
我想找出每个变量的名字(比如 FOO1、BAR2、BOOP),同时忽略掉任何逻辑运算符(比如 AND、OR、NOT)。
这是我尝试的解决办法:(?!AND)(?!OR)(?!NOT)([a-zA-Z0-9]+)
我在让这些“前瞻”部分识别 AND、OR、NOT 时遇到了麻烦,因为它们被当作单独的字符而不是一个完整的词。
如果有人能帮忙就太好了,非常感谢!
2 个回答
你需要使用一个单词边界(\b
)。这个东西很有用,可以帮助你找到一个单词的开始或结束。它的工作原理是进行一个零长度的断言(也就是说,它实际上并不匹配任何东西,有点像锚点 ^
和 $
),在 (^\w|\w\W|\W\w|\w$)
上进行检查。换句话说,它确保一个单词(\w
等于 [a-zA-Z0-9_]
)旁边有一个非单词字符,或者是在字符串的开始或结束。你也可以把你的表达式组合起来(而且捕获组可能并不是必需的):
\b(?!AND|OR|NOT)[a-zA-Z0-9]+
注意,在表达式的末尾不需要单词边界,因为正则表达式是贪婪的,会尽可能多地匹配 [a-zA-Z0-9]+
。
如果你的变量中可以包含下划线(_
),那么使用 \w
这个简写字符类可能会更简洁(正如上面提到的,它和 [a-zA-Z0-9_]
是一样的)。最终的表达式将是:
\b(?!AND|OR|NOT)\w+
顺便提一下,(?!...)
是一个负向前瞻,而不是负向后顾(它确保引擎内部指针前面的字符不匹配 ...
)。
首先,感谢你分享你的尝试。接下来,我们来看看怎么改进你的正则表达式,让它更简单:
你已经有了一些不错的前瞻(lookaheads),我们可以把它简化成:
(?!AND|OR|NOT)([a-zA-Z0-9]+)
其实我们不需要捕获组
(?!AND|OR|NOT)[a-zA-Z0-9]+
我们可以加一个单词边界,这样可以防止部分匹配,变成
(?!AND|OR|NOT)\b[a-zA-Z0-9]+
举个例子,输入 foo AND bar
:
foo AND bar
^ Checks if there is no "AND", "OR" or "NOT" literally
since there isn't, it will match foo with [a-zA-Z0-9]+
foo AND bar
^ no match
foo AND bar
^ Here it will fail because of the negative lookahead
foo AND bar
^ It will succeed because there is no "AND", "OR" or "NOT" literally
所以解决方案是加一个单词边界 \b
,这和 (?<!\w)
是一样的。这意味着如果后面有一个单词字符,正则表达式就会失败。
foo AND bar
^ fail, because there is a word character behind
foo AND bar
^^^ match