Python正则表达式:如何仅捕获精确匹配,排除#apple中的apple
问题:正则匹配时避免同时捕获带#的标签及其中的单词
以下是当前使用的代码:
import re fruit_list = ['apple banana', 'apple', 'pineapple', 'banana', 'banana apple', 'kiwi'] fruit = re.compile('|'.join(fruit_list)) fruit_re = [ re.compile(r'\b('+re.escape(fruit)+r')\b') for fruit in fruit_list] fruit_re.append(re.compile( r'([#@])(\w+)')) string = "this is pooapple is banana apple #apple" for ft in fruit_re: match = re.finditer(ft, string) print(type(match)) for mat in match: print(mat.span()) print(mat.group()) print("****************")
当前代码的问题是:会同时捕获#apple(位置33,39)以及其中的apple(位置34,39),运行输出如下:
(27, 32) apple **************** (34, 39) apple **************** <class 'callable_iterator'> <class 'callable_iterator'> (20, 26) banana **************** <class 'callable_iterator'> (20, 32) banana apple **************** <class 'callable_iterator'> <class 'callable_iterator'> (33, 39) #apple ****************
需求是仅捕获#apple,不捕获其中的apple,该如何实现?
解决方案
核心思路是让匹配水果单词的正则排除掉紧跟在#或@后面的单词,通过添加负向零宽断言即可实现:
修改生成fruit_re的正则表达式,在单词边界前加入(?<![#@]),确保匹配的单词前面不是#或@符号:
import re fruit_list = ['apple banana', 'apple', 'pineapple', 'banana', 'banana apple', 'kiwi'] # 新增负向后行断言,排除#/@后的单词匹配 fruit_re = [ re.compile(r'(?<![#@])\b('+re.escape(fruit)+r')\b') for fruit in fruit_list] fruit_re.append(re.compile( r'([#@])(\w+)')) string = "this is pooapple is banana apple #apple" for ft in fruit_re: match = re.finditer(ft, string) print(type(match)) for mat in match: print(mat.span()) print(mat.group()) print("****************")
修改后的运行输出将不再包含#apple中的apple匹配项,只会保留正常的水果单词和完整的标签匹配结果。
原理说明
(?<![#@])是负向后行断言,表示当前位置的前一个字符不能是#或@。当正则尝试匹配#apple里的apple时,因为apple前面是#,不满足断言条件,就会被自动排除。
内容的提问来源于stack exchange,提问作者tkansara
相关产品推荐
相关产品推荐

