连接以引用打印格式编码的行

连接以引用打印格式编码的行

我有一个巨大的 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,则它已经被发现为字节字符串。)

相关内容