脚本查找单词A和单词b之间的文本字符串.findstr、Regex或替代品



我最近收到了大量的电子邮件要分析。副本被转换成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这样的编程语言是一种更可行、更经得起未来考验的匹配。

那么编程任务有两部分:

  1. 遍历目录树以访问每个文件
  2. 查找每个文件内容中的列表

至于后者,正则表达式看起来确实是一种可行的机制,但第一个问题是,你能负担得起吗?很明显,我们需要多行处理,而且每次我看到这样做的时候,都是一次处理整个文件。您能负担得起将整个文件读入内存的费用吗?您能负担得起从磁盘读取整个文件吗?也许头文件位于文件顶部,读取整个文件体是浪费的?我想没有问题了。

使用单个正则表达式直接从文件中提取单个附件名称似乎非常复杂(即使在支持重复捕获的语言中也是如此)。所以我会让正则表达式先找到列表,然后再拆分它。甚至不考虑.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'。

最新更新