如何用Python正则匹配#前不含abc/def/ghi(单词边界)的字符串
解决Python正则筛选#前不含指定单词边界字符串的问题
需求是从列表中筛选出**#符号之前任意位置均不包含作为单词边界的abc、def或ghi**的字符串,示例列表和预期输出如下:
示例列表:
l = [ "he is abc but # not xyz", "he is good # but small", "he might ghi but # not abc will", "he will help but # hope for def to come", "he is going for vabc but # not sure" ]
预期输出:
["he is good # but small", "he will help but # hope for def to come", "he is going for vabc but # not sure"]
你之前用的正则^(?!.*\b(?:abc|def|ghi)\b).*#无法得到预期结果,问题出在这个正则的负向预查是断言整个字符串都不能出现目标单词,但需求只限制#之前的部分,#之后出现abc/def/ghi是允许的——比如预期输出里的"he will help but # hope for def to come",#之后的def是符合要求的,但原正则会因为整个字符串包含def而把它排除。
正确的正则写法及实现
我们需要把检查范围限定在#之前的内容,确保这部分里没有作为单词边界的目标单词。可以用下面的代码实现:
import re l = [ "he is abc but # not xyz", "he is good # but small", "he might ghi but # not abc will", "he will help but # hope for def to come", "he is going for vabc but # not sure" ] # 正则说明:确保#之前的所有内容都不包含作为单词边界的abc/def/ghi pattern = re.compile(r'^((?!\b(abc|def|ghi)\b).)*#.*') result = [s for s in l if pattern.match(s)] print(result)
运行后会得到预期的输出结果。
正则解释
^:锚定字符串开头((?!\b(abc|def|ghi)\b).)*:循环的负向预查,意思是每匹配一个字符前,都断言当前位置之后不会出现带单词边界的abc/def/ghi。这个循环会一直匹配到#出现,确保#之前的所有内容都符合要求。#.*:匹配#符号以及后面的所有内容,确保字符串包含#(符合筛选的前提)
另外也可以用另一种等价写法,逻辑更直观:断言字符串中不存在“目标单词出现在#之前”的情况:
pattern = re.compile(r'^(?!.*\b(?:abc|def|ghi)\b(?=.*#)).*')
这个正则里的(?=.*#)是正向预查,用来限定目标单词的位置必须在#之前,整个负向预查就表示“不存在这样的目标单词”,同样能满足需求。
内容的提问来源于stack exchange,提问作者Cassius Clay
相关产品推荐
相关产品推荐

