我已经在网站上找到了该问题的答案,并用尽了Google的精力和耐心尝试自己回答的问题,这里就是。如果这是骗子,很高兴指出答案。
所以我有一个很长的正则表达式-没什么复杂的,只是一堆简单的条件而已。我正在使用它从我从新闻文章数据中提取的命名实体的开头和结尾中删除管道词。用例是,许多名称中都包含这些简短的单词(请考虑疾病控制和预防中心),但是我想删除出现在名称开头或结尾的单词。例如,出于明显的原因,我不希望“疾病控制中心”与“ 疾病控制中心”的计数不同。
我使用以下代码(file here)在Python 3.7.2中的大量(> 1M)命名实体列表上使用了此正则表达式字符串:
with open('pnames.csv','r') as f:
named_entities = f.read().splitlines()
print(len([i for i in named_entities if i == 'the wall street journal']))
# 146
short_words = "^and\s|\sand$|^at\s|\sat$|^by\s|\sby$|^for\s|\sfor$|^in\s|\sin$|^of\s|\sof$|^on\s|\son$|^the\s|\sthe$|^to\s|\sto$"
cleaned_entities = [re.sub(short_words,"",i)
for i
in named_entities]
print(len([i for i in cleaned_entities
if i == 'the wall street journal']))
# 80 (huh, should be 0. Let me try again...)
cleaned_entities2 = [re.sub(short_words,"",i)
for i
in cleaned_entities]
print(len([i for i in cleaned_entities2
if i == 'the wall street journal']))
# 1 (better, but still unexpected. One more time...)
cleaned_entities3 = [re.sub(short_words,"",i)
for i
in cleaned_entities2]
print(len([i for i in cleaned_entities3
if i == 'the wall street journal']))
# 0 (this is what I expected on the first run!)
我的问题是,为什么正则表达式不能一次删除所有匹配的子字符串?即len([i for i in cleaned_entities if i == 'the wall street journal'])
为什么不等于0?为什么需要多次运行才能完成工作?
我尝试过的事情:
"^the "
(一次性修复所有匹配项)是的,任何想法都会有所帮助。
答案 0 :(得分:1)
您的正则表达式每次通过只会删除一层不需要的单词。所以如果你有一个 句子为:
and and at by in of the the wall street journal at the by on the
它需要很多遍才能完全删除所有内容。
可以重新排列该表达式以使用+
来表示一个或多个事件,如下所示:
import re
with open('pnames2.csv','r') as f:
named_entities = f.read().splitlines()
print(len([i for i in named_entities if i == 'the wall street journal']))
# 146
short_words = "^((and|at|by|for|in|of|on|the|to)\s)+|(\s(and|at|by|for|in|of|on|the|to))+$"
re_sw = re.compile(short_words)
cleaned_entities = [re_sw.sub("", i) for i in named_entities]
print(len([i for i in cleaned_entities if i == 'the wall street journal']))
# 0
可以通过预编译正则表达式来稍微加快该过程。如果将它应用于 整个文件,而不是逐行应用。