用于查找单词A和单词B之间的文本字符串的脚本。findstr、Regex或替代项
我最近收到了大量的电子邮件要分析。副本被转换成txt和html文件,并提取到相同的子目录中。然后,数据按字段代码排序,并使用各种cmd/batch脚本输入电子表格。后来,有必要确定产生问题的每个附件的文件名 findstr能够使用以下命令成功识别每个附件的路径、电子邮件和文件名,并将其保存到输出日志中:用于查找单词A和单词B之间的文本字符串的脚本。findstr、Regex或替代项,regex,batch-file,cmd,Regex,Batch File,Cmd,我最近收到了大量的电子邮件要分析。副本被转换成txt和html文件,并提取到相同的子目录中。然后,数据按字段代码排序,并使用各种cmd/batch脚本输入电子表格。后来,有必要确定产生问题的每个附件的文件名 findstr能够使用以下命令成功识别每个附件的路径、电子邮件和文件名,并将其保存到输出日志中: findstr /s Attachments: *.* >>Find_Attachments_Files2.txt 不幸的是,findstr只会找到单词“Attachments:”
findstr /s Attachments: *.* >>Find_Attachments_Files2.txt
不幸的是,findstr只会找到单词“Attachments:”后面的第一个文件名,仅此而已。
我需要找到,和log,路径、文件以及“附件:”和第二个标记之间的每一个文本块,在本例中,是一系列破折号(“---”),除此之外什么都没有
文本消息的格式类似于下面显示的格式,不限于任何固定值/行#:
来自:“老鼠,米奇”米奇。Mouse@mouseclick.com 捕获marker1和marker2之间的文本块的能力非常重要,解决这个特定问题的方法是一个更广泛的问题,应该相应地加以阐述。虽然搜索和替换功能很有价值,但搜索和报告功能可能是所有功能中最有价值的
是什么使这一点如此不完美和困难?有什么建议或可靠的解决方案吗?我对此的看法,从高到低 为什么这是不完美和困难的?因为,尽管你非常努力地改进了这个问题,它仍然有很多未定义的地方,但它已经相当复杂了。幸运的是,其他人也对文本文件进行了类似的探索,并开发了完整的编程语言来处理这些问题。但是,即使你已经彻底地了解了其中的一些,你仍然会被咬,因为按照你的规范操作的计算机是令人震惊的愚蠢。快,但愚蠢 使用一些开箱即用的东西,比如findstr,egrep。。。处理这个问题对我来说几乎是不可能的。像Python这样的编程语言是一种更为可行和经得起未来考验的匹配 因此,编程任务有两个部分:
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”。我不确定这是否可行,这只是一个理论,但我认为值得一试 我认为findstr命令在完成执行后可能会发出errorlevel。如果找到字符串时的errorlevel不同。如果找不到字符串,则返回另一个errorlevel 如果这确实有效,那么您可以执行类似于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的文本文件中。事实上,python的
re
可能更适合此操作,Python是我能够将原始Outlook.msg消息提取为任何其他可用格式的唯一方法。一句话:Python的功能给人留下了深刻的印象,但只是缺乏经验。对不起。您是否有许多文件,每个文件都有一个部分,如图所示?或者您有一个包含多个部分的大文件,如图所示?还有其他可能性吗?@Aacini抱歉我之前没看到,这很重要。许多文件-许多子目录,不超过3级-路径必须位于每个文件名之前,后跟附件文件名,最好用选项卡分隔。Html文件的格式与上面的示例类似。Txt文件类似,除了“Headers:”替换为“----”(非常长的破折号字符串)。输出应该类似于我问题中的findstr命令,如下所示:R:\Emails\Inbox\000023 Estimated revenue questions.txt Estimated revenue_Mar_08.xls(29232)您更改了问题。提供虚假的细节以获得准确的编程概念和代码应该被视为一种严重的罪行。
: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