Python 根据感兴趣的单词词典,从电子邮件列表中识别最常出现的单词
目录D包含几千封.eml格式的电子邮件。有些电子邮件是纯文本的,有些来自Outlook,有些有ASCII头和HTML/MIME内容,等等。存在一个字典文件F,其中包含要在D目录下的文件中查找的感兴趣单词列表(即红色\n蓝色\n绿色\n…)。D目录有大量子文件夹,但除了上面提到的.eml文件之外,没有其他文件。应根据以下规范列出最常出现的单词:Python 根据感兴趣的单词词典,从电子邮件列表中识别最常出现的单词,python,regex,bash,parallel-processing,grep,Python,Regex,Bash,Parallel Processing,Grep,目录D包含几千封.eml格式的电子邮件。有些电子邮件是纯文本的,有些来自Outlook,有些有ASCII头和HTML/MIME内容,等等。存在一个字典文件F,其中包含要在D目录下的文件中查找的感兴趣单词列表(即红色\n蓝色\n绿色\n…)。D目录有大量子文件夹,但除了上面提到的.eml文件之外,没有其他文件。应根据以下规范列出最常出现的单词: 对于每一个有趣的单词,都应该提供关于它出现多少次以及在哪里出现的信息。如果它在一个文件中多次出现,则应该为该文件报告多次。报告事件意味着报告整数元组(L
- 对于每一个有趣的单词,都应该提供关于它出现多少次以及在哪里出现的信息。如果它在一个文件中多次出现,则应该为该文件报告多次。报告事件意味着报告整数元组(L,P),其中L是电子邮件源顶部的行号,P是该行中事件开始的位置
- Bash/gnucli工具(特别是通过GNU'parallel'可并行的东西,仅用于CLI执行)
- Python(NLP?)
- 信用证++
- 我们不希望按照“对于所有电子邮件,执行正则表达式搜索并执行_something();”的方式来执行操作。我可以想象大多数电子邮件的长度比有趣的单词列表要短,所以我会尝试单独处理每封电子邮件并提取必要的信息
- 构建专门的字符串数据结构(例如or),以快速查找单词是否有趣。我有很好的经验建立一个三元搜索树的话,因为它允许快速查找的话
- 然后,算法将如下所示:
结果一些备注:
- 我们不希望按照“对于所有电子邮件,执行正则表达式搜索并执行_something();”的方式来执行操作。我可以想象大多数电子邮件的长度比有趣的单词列表要短,所以我会尝试单独处理每封电子邮件并提取必要的信息
- 构建专门的字符串数据结构(例如or),以快速查找单词是否有趣。我有很好的经验建立一个三元搜索树的话,因为它允许快速查找的话
- 然后,算法将如下所示:
(当然是伪代码)
resultPython:
list = ['a', 'bunch', 'of', 'interesting', 'words']
linepos = 0
with open("file") as f:
for line in f:
linepos += 1
wordpos = 0
for word in line.split():
wordpos += 1
if word in list:
print "%s found at line %s, word %s" % (word, linepos, wordpos)
Python:
list = ['a', 'bunch', 'of', 'interesting', 'words']
linepos = 0
with open("file") as f:
for line in f:
linepos += 1
wordpos = 0
for word in line.split():
wordpos += 1
if word in list:
print "%s found at line %s, word %s" % (word, linepos, wordpos)
我假设您可以创建/找到一个eml到文本的转换器。那么这就非常接近你想要的了:
find -type f | parallel --tag 'eml-to-text {} | grep -o -n -b -f /tmp/list_of_interesting_words'
输出未按您的要求100%格式化:
文件名\t行号:字节号(从文件开头):word
如果您有许多有趣的单词,则grep
中的“-f”启动速度很慢,因此如果您可以创建maildir的未打包版本,则可以使并行启动grep
的次数减少:
find . -type f | parallel 'eml-to-text {} >/tmp/unpacked/{#}'
find /tmp/unpacked -type f | parallel -X grep -H -o -n -b -f /tmp/list_of_interesting_words
由于grep-f
的时间复杂度比线性复杂度差,您可能需要将/tmp/list\u有趣的单词分成更小的块:
cat /tmp/list_of_interesting_words | parallel --pipe --block 10k --files > /tmp/blocks_of_words
然后并行处理块和文件:
find /tmp/unpacked -type f | parallel -j1 -I ,, parallel --arg-file-sep // -X grep -H -o -n -b -f ,, {} // - :::: /tmp/blocks_of_words
此输出的格式如下:
文件名:行号:字节号(从文件开头):word
要按word
而不是文件名对其进行分组,请通过排序对结果进行管道排序:
... | sort -k4 -t: > index.by.word
要计算频率,请执行以下操作:
... | sort -k4 -t: | tee index.by.word | awk 'FS=":" {print $4}' | uniq -c
好消息是,这应该相当快,我怀疑您是否能够使用Python实现同样的速度
编辑:
grep-F在开始时要快得多,并且您需要-w表示grep(因此单词'gram'与'diagrams'不匹配);这也将避免临时文件,并且可能相当快:
find . -type f | parallel --tag 'eml-to-text {} | grep -F -w -o -n -b -f /tmp/list_of_interesting_words' | sort -k3 -t: | tee index.by.word | awk 'FS=":" {print $3}' | uniq -c
我假设您可以创建/找到一个eml到文本的转换器。那么这就非常接近你想要的了:
find -type f | parallel --tag 'eml-to-text {} | grep -o -n -b -f /tmp/list_of_interesting_words'
输出未按您的要求100%格式化:
文件名\t行号:字节号(从文件开头):word
如果你有很多有趣的单词,grep
中的'-f'启动速度很慢,因此如果你能创建一个u