在单词A和单词B之间查找文本字符串的脚本。findstr、正则表达式或其他替代方案。

3

最近我被分配了一大批电子邮件来分析。复制后转换为txt和html文件,并提取到相同的子目录中。然后,使用各种cmd/batch脚本按字段代码对数据进行排序,并输入到电子表格中。后来,需要识别每个附件的文件名,这成为一个问题。

使用以下命令,findstr能够成功识别每个附件的路径、电子邮件消息和文件名,并将其保存到输出日志中:

findstr /s Attachments: *.* >>Find_Attachments_Files2.txt

很遗憾,findstr只能找到“Attachments:”后面的第一个文件名,而不能找到更多。 我需要找到,并记录,“附件:”和第二个标记之间的路径、文件和每个文本块,在本例中是一系列破折号(“----”),不包括之后的任何内容。

文本消息类似于下面显示的格式,没有固定的值/行号限制:

Attachments: Purely Practical.pdf  
Daily Revenue.xls  
Advertising_Ideas.doc 

发件人: "Mouse, Mickey" Mickey.Mouse@mouseclick.com

能够捕获标记1和标记2之间的文本块是极为重要的,解决这个特定问题的方案是一个更广泛的问题,应该相应地进行框架设计。虽然搜索和替换功能具有很大的价值,但搜索和报告功能可能是最有价值的。

这使得它如此不完美和困难?有什么建议或可靠的解决方案吗?


也许Python的re更适合这个。 - Monacraft
事实上,Python 是我唯一能够将原始的 Outlook .msg 消息提取到任何其他可用格式的方式。总之:非常 impressed by Python 的功能,但缺乏经验。 - UberGeek
请问,您有许多文件,每个文件都有一个像所示的部分吗?还是您只有一个大文件,其中包含几个像所示的部分?还有其他可能性吗? - Aacini
@Aacini 抱歉我之前没看到,这很重要。有许多文件 - 许多子目录,但没有超过3个级别 - 每个文件名前必须有路径,后面跟着附件文件名,最好用制表符分隔。Html文件的格式如上例所示。Txt文件类似,只是“Headers:”被“-----”(非常长的破折号字符串)替换。输出应该类似于我的问题中的findstr命令,如下所示:R:\Emails\Inbox\000023Estimated revenue questions.txt Estimated Revenue_Mar_08.xls (29,232) - UberGeek
1
你改变了问题。为了获取精确的编程概念和代码而提供虚假信息应该被视为一种极其恶劣的行为。 - foxidrive
挫败、内疚,现在还有一个悬而未决的问题!通过澄清我的原始问题,我从未打算欺骗。我以为我们正在共同解决问题。请原谅我。 - UberGeek
2个回答

1
我不确定这个方法是否有效,这只是一个理论,但我认为值得一试。
我认为可能性是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命令 >> log.txt :: 这将把命令的输出保存到名为log的文本文件中。

0

从高到低,这是我的看法...

为什么这很不完美且困难?因为尽管你很勤奋地改进了问题,但它仍然有很多未定义的地方,而且已经相当复杂了。幸运的是,其他人也研究过文本文件,并开发了整个编程语言来处理它们。但即使你已经彻底学习了其中一些,你仍然会受到影响,因为按照你的规范操作的计算机非常愚蠢。快速,但愚蠢。

对于像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("%s\t%s\n" % (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: Stuff\n" +
                    "Attachments: Purely Practical.pdf\n" +
                    "Daily Revenue.xls\n" +  
                    "Advertising_Ideas.doc\n" +
                    "-------------\n" +
                    'From: "Mouse, Mickey" Mickey.Mouse@mouseclick.com\n')
    def runTest(self):
        self.walkthewalk()
        self.assertEqual(self.out.getvalue().replace(self.tempdir.name + os.sep, "{p}"), 
            "{p}friend\tPurely Practical.pdf\n" +
            "{p}friend\tDaily Revenue.xls\n" +
            "{p}friend\tAdvertising_Ideas.doc\n")

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 enemy\n" +
                    "\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'。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接