匹配所有字符,但排除某些词

1 投票
2 回答
1167 浏览
提问于 2025-04-18 13:19

我这几天在学习正则表达式(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 个回答

1

你需要使用一个单词边界(\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+

顺便提一下,(?!...) 是一个负向前瞻,而不是负向后顾(它确保引擎内部指针前面的字符不匹配 ...)。

2

首先,感谢你分享你的尝试。接下来,我们来看看怎么改进你的正则表达式,让它更简单:

  1. 你已经有了一些不错的前瞻(lookaheads),我们可以把它简化成:(?!AND|OR|NOT)([a-zA-Z0-9]+)

  2. 其实我们不需要捕获组 (?!AND|OR|NOT)[a-zA-Z0-9]+

  3. 我们可以加一个单词边界,这样可以防止部分匹配,变成 (?!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

在线演示

撰写回答