我有一个巨大的 mbox 文件 (8.8 GB),其中包含许多引用的可打印附件,由 75 个字符的行组成,以“软换行”序列(等号、回车、换行)终止。
我想搜索 mbox 内容中所有出现的特定正则表达式。但是,任何特定的匹配都可能分为多行,因此我需要在执行正则表达式搜索之前删除每个软换行序列。
我很难找出最好的方法来做到这一点。我找到的 GNU sed 解决方案这里失败,因为它显然指示 sed 将整个文件视为一行。该行的长度大于INT_MAX
,这会导致 sed 退出并显示错误消息。我也看到有一个解决方案这里使用 ripgrep 。然而,这并没有真正加入队伍;等号被删除,但带有等号的行仍然与下一行分开。
答案1
最后,您所描述的您正在做的是将 mbox 解析为电子邮件内容(我将其附件计算在内),然后查看这些内容。正确的做法!
因此,这样做:将 mbox 文件实际上解析为邮件,您会感到有点高兴。这是我的头顶,拼凑在一起,未经测试,但在我的编辑器代码中不是红色的:
#!/usr/bin/env python3
import mailbox
import re as regex
pattern = regex.compile("BRIANSREGEX")
mb = mailbox.mbox("Briansmails.mbox", create=False)
for msg in mb:
print(f"{msg['Subject']}")
for part in msg.walk():
print(f"| {part.get_content_type()}, {part.get_content_charset()}")
print("-"*120)
payload = part.get_payload(decode=True)
charset = part.get_content_charset
if type(payload) is bytes:
content = ""
try:
content = payload.decode(charset)
except:
# print("failed to decode")
try:
content = payload.decode() # try ascii
match = pattern.search(content)
# do what you want with that match…
if match:
print(f"| matched at {match.start()}")
print("-"*120)
答案2
我对 Marcus Müller 的回答表示赞赏,但这是我最终使用的版本,它基于他的回答:
#!/usr/bin/env python3
import mailbox
import re
import sys
byte_pattern = re.compile(b"https?://[^/]*imgur.com/[a-zA-Z0-9/.]*")
str_pattern = re.compile("https?://[^/]*imgur.com/[a-zA-Z0-9/.]*")
mb = mailbox.mbox(sys.argv[1], create=False)
for msg in mb:
for part in msg.walk():
if part.is_multipart():
continue
payload = part.get_payload(decode=True)
if type(payload) is bytes:
# first, search it as a binary string
for match in byte_pattern.findall(payload):
print(match.decode('ascii'))
# then, try to decode it in case it's utf-16 or something weird
charset = part.get_content_charset()
if charset and charset != 'utf-8':
try:
content = payload.decode(charset)
for match in str_pattern.findall(content):
print(match)
except:
pass
else:
print('failed to get message part as bytes')
请注意,它part
可能是多部分消息,即不是树中的叶节点,因为walk
执行包括非叶节点的深度优先遍历。
仅当它是叶节点时,我首先将模式作为字节字符串进行搜索,然后尝试使用指定的字符集将其解码为文本(如果它不是 UTF-8)。 (如果是最常见的 UTF-8,则它已经被发现为字节字符串。)