我是编程和正则表达式方面的新手,如果之前有人问过这个问题,我深表歉意(不过我没有找到)。
我想使用 Python 来汇总文字文本中的词频。假设文本的格式类似于
Chapter 1
blah blah blah
Chapter 2
blah blah blah
....
现在我将文本作为字符串读取,我想使用re.findall 来获取这段文本中的每个单词,所以我的代码是
wordlist = re.findall(r'\b\w+\b', text)
但问题是它与每个章节标题中的所有这些 Chapter 匹配,我不想将其包含在我的统计信息中。所以我想忽略匹配 Chapter\s*\d+ 的内容。我该怎么办?
在此先感谢各位。
请您参考如下方法:
解决方案
您可以先删除所有 Chapter+space+digits :
wordlist = re.findall(r'\b\w+\b', re.sub(r'Chapter\s*\d+\s*','',text))
如果您只想使用一次搜索,您可以使用否定先行查找前面没有“第 X 章”且不以数字开头的任何单词:
wordlist = re.findall(r'\b(?!Chapter\s+\d+)[A-Za-z]\w*\b',text)
如果性能是个问题,加载一个巨大的字符串并用 Regex 解析它无论如何都不是正确的方法。只需逐行读取文件,抛出任何匹配 r'^Chapter\s*\d+' 的行,然后用 r'\b\w+\b'< 分别解析剩余的每一行 :
import re
lines=open("huge_file.txt", "r").readlines()
wordlist = []
chapter = re.compile(r'^Chapter\s*\d+')
words = re.compile(r'\b\w+\b')
for line in lines:
if not chapter.match(line):
wordlist.extend(words.findall(line))
print len(wordlist)
性能
我写了一个小的 ruby 脚本来写一个大文件:
all_dicts = Dir["/usr/share/dict/*"].map{|dict|
File.readlines(dict)
}.flatten
File.open('huge_file.txt','w+') do |txt|
newline=true
txt.puts "Chapter #{rand(1000)}"
50_000_000.times do
if rand<0.05
txt.puts
txt.puts
txt.puts "Chapter #{rand(1000)}"
newline = true
end
txt.write " " unless newline
newline = false
txt.write all_dicts.sample.chomp
if rand<0.10
txt.puts
newline = true
end
end
end
生成的文件有超过 5000 万个单词,大约 483MB 大:
Chapter 154
schoolyard trashcan's holly's continuations
Chapter 814
assure sect's Trippe's bisexuality inexperience
Dumbledore's cafeteria's rubdown hamlet Xi'an guillotine tract concave afflicts amenity hurriedly whistled
Carranza
loudest cloudburst's
Chapter 142
spender's
vests
Ladoga
Chapter 896
petition's Vijayawada Lila faucets
addendum Monticello swiftness's plunder's outrage Lenny tractor figure astrakhan etiology's
coffeehouse erroneously Max platinum's catbird succumbed nonetheless Nissan Yankees solicitor turmeric's regenerate foulness firefight
spyglass
disembarkation athletics drumsticks Dewey's clematises tightness tepid kaleidoscope Sadducee Cheerios's
两步过程平均需要 12.2 秒来提取词表,前瞻方法需要 13.5 秒,Wiktor 的答案也需要 13.5 秒。我最先写的lookahead方法使用了re.IGNORECASE,耗时18s左右。
在读取整个文件时,所有 Regexen 方法之间的性能基本上没有差异。
但令我惊讶的是,readlines 脚本花费了大约 20.5 秒,并且使用的内存并不比其他脚本少多少。如果您对如何改进脚本有任何想法,请发表评论!
