我最近收到了大量的电子邮件要分析。副本被转换成txt和html文件,并提取到相同的子目录中。然后,数据按字段代码排序,并使用各种cmd/批处理脚本输入电子表格。后来,有必要确定每个产生问题的附件的文件名。
findstr能够成功地识别每个附件的路径、电子邮件消息和文件名,并使用下面的命令将其保存到输出日志中:
findstr /s Attachments: *.* >>Find_Attachments_Files2.txt
不幸的是,findstr只会找到单词"Attachments:"之后的第一个文件名,除此之外什么也找不到。我需要找到,和日志,路径,文件和"附件:"和第二个标记之间的每个文本块,在这种情况下,一系列破折号("----"),没有别的。
文本消息类似于下面所示的格式,并且不限于任何固定值/line #:
Attachments: Purely Practical.pdf
Daily Revenue.xls
Advertising_Ideas.doc
选自:《米老鼠》Mickey.Mouse@mouseclick.com
捕获marker1和marker2之间的文本块的能力是非常重要的,对这个特殊问题的解决方案是一个更广泛的问题,应该相应地构建。虽然搜索和替换功能很有价值,但搜索和报告功能可能是所有功能中最有价值的。
是什么让它如此不完美和困难?有什么建议或可靠的解决方案吗?
我不确定这是否会起作用,这只是一个理论,但我认为值得一试。
我认为findstr命令在完成执行后可能会给出一个错误级别。如果错误级别与查找字符串时的错误级别不同。如果没有找到字符串,则返回不同的错误级别。
如果这确实有效,那么你可以做一些类似于while循环的事情,例如
:A
findstr :: And then the full command
if errorlevel == 1 goto A :: If the string has been found
goto B :: The rest of your code
这只是理论上的
要保存输出,您应该能够像这样做echo command>>log.txt::这将把命令的输出保存到名为log的文本文件中。
我的看法,从高到低…
为什么这是不完美的和困难的?因为,尽管你很勤奋地改进了这个问题,但它仍然有很多未定义的地方,而且它已经相当复杂了。幸运的是,其他人已经对文本文件进行了类似的研究,并且开发了完整的编程语言来处理这个问题。但是,即使您已经彻底了解了其中的一些,您仍然会感到困惑,因为按照您的规范运行的计算机非常愚蠢。快,但愚蠢。
使用一些开箱即用的东西,如findstr, egrep…处理这个特殊的问题对我来说几乎是不可能的。像Python这样的编程语言是一种更可行、更经得起未来考验的匹配。
那么编程任务有两部分:
- 遍历目录树以访问每个文件
- 查找每个文件内容中的列表
至于后者,正则表达式看起来确实是一种可行的机制,但第一个问题是,你能负担得起吗?很明显,我们需要多行处理,而且每次我看到这样做的时候,都是一次处理整个文件。您能负担得起将整个文件读入内存的费用吗?您能负担得起从磁盘读取整个文件吗?也许头文件位于文件顶部,读取整个文件体是浪费的?我想没有问题了。
使用单个正则表达式直接从文件中提取单个附件名称似乎非常复杂(即使在支持重复捕获的语言中也是如此)。所以我会让正则表达式先找到列表,然后再拆分它。甚至不考虑.txt文件是什么意思,并且隐藏的测试用例太少,这将我们带到了:
import os
import re
searcher = re.compile(r"^Attachments: (.+?)^---+$", flags=re.MULTILINE+re.DOTALL)
def visitFile(filepath, out):
with open(filepath) as f:
match = searcher.search(f.read())
if match:
for name in match.group(1).split('n')[:-1]:
out.write("%st%sn" % (filepath, name))
def visitFolder(topdirpath, out):
for dirpath, subdirnames, filenames in os.walk(topdirpath):
subdirnames.sort() # if needed
filenames.sort() # if needed
for filename in filenames:
visitFile(os.path.join(dirpath, filename), out)
if __name__ == "main":
visitFolder(sys.argv[1], sys.out)
import io
import tempfile
import unittest
class FolderBasedTestCase(unittest.TestCase):
def setUp(self):
self.tempdir = tempfile.TemporaryDirectory(prefix="test_dir_")
self.out = io.StringIO()
def tearDown(self):
self.tempdir.cleanup()
self.out.close()
def walkthewalk(self):
visitFolder(self.tempdir.name, self.out)
class EmptyFolderTestCase(FolderBasedTestCase):
def runTest(self):
self.walkthewalk()
self.assertEqual(self.out.getvalue(), "")
class FriendTestCase(FolderBasedTestCase):
def setUp(self):
super().setUp()
with open(os.path.join(self.tempdir.name, "friend"), "w") as f:
f.write("Some: Stuffn" +
"Attachments: Purely Practical.pdfn" +
"Daily Revenue.xlsn" +
"Advertising_Ideas.docn" +
"-------------n" +
'From: "Mouse, Mickey" Mickey.Mouse@mouseclick.comn')
def runTest(self):
self.walkthewalk()
self.assertEqual(self.out.getvalue().replace(self.tempdir.name + os.sep, "{p}"),
"{p}friendtPurely Practical.pdfn" +
"{p}friendtDaily Revenue.xlsn" +
"{p}friendtAdvertising_Ideas.docn")
class FooTestCase(FolderBasedTestCase):
def setUp(self):
super().setUp()
with open(os.path.join(self.tempdir.name, "foo"), "w") as f:
f.write("From: your worst enemyn" +
"n" +
"Mail body here. This week's topics:n" +
"Attachments: are't they a pain?n" +
"Pain: don't we get attached to it?n" +
"n")
def runTest(self):
self.walkthewalk()
self.assertEqual(self.out.getvalue(), "")
请注意,正则表达式(希望)独立于文件的换行风格,但是,就目前而言,split()
需要正确的行分隔符。
我怀疑单独编译和存储正则表达式有任何性能上的好处,任何人都不会注意到,但我认为对于这一小部分代码,它实际上使东西更可读。
要运行单元测试,特别是如果您将代码和测试用例都存储在单个文件scriptname.py中,请执行' python -m unittest scriptname'。