如何捕获二进制字符串中的所有字符而不被Python解释

3 投票
4 回答
533 浏览
提问于 2025-04-16 19:10

这是我重现问题的方法:

首先,创建一个叫做'temp.log'的日志文件,并把这一行粘贴进去:

DEBUG: packetReceived '\x61\x62\x63'

我想要一个脚本,它可以读取日志文件中的这一行,并解码其中的二进制字符串部分('\x61\x62\x63')。为了进行解码,我使用了struct模块,所以:

struct.unpack('BBB', '\x61\x62\x63')

这应该能给我:

(97, 98, 99)

这是我正在使用的脚本:

import re
import struct
import sys

f = open(sys.argv[1], 'r')
for line in f:
    print line
    packet = re.compile(r"packetReceived \'(.*)\'").search(line).group(1)

    # packet is the string r'\x61\x62\x63'
    assert(len(packet), 12)

    # this works ok (returns (97, 98, 99))
    struct.unpack('BBB', '\x61\x62\x63')

    # this fails because packet is interpreted as r'\\x61\\x62\x63'
    struct.unpack('BBB', packet)

我运行这个脚本时,把temp.log作为参数传给它。

希望我的注释能突出我的问题。我该如何让变量packet被解释为'\x61\x62\x63'呢?

顺便说一下:在这个问题的第一次编辑中,我以为从文件中读取这一行和这样做是一样的:

line = "DEBUG: packetReceived '\x61\x62\x63'"

这会让packet等于'abc'。

但实际上,它和这样做是一样的(使用原始字符串):

line = r"DEBUG: packetReceived '\x61\x62\x63'"

4 个回答

2
>>> re.compile(r"packetReceived '(.*)'").search(r"DEBUG: packetReceived '\x61\x62\x63'").group(1)
'\\x61\\x62\\x63'

不,这一行不是你问题的所在。

5

Python 在处理正则表达式时,不会对你传入的字符串进行解释。那些转义序列(比如 \n、\t 等)很可能在你定义变量 line 时就已经被解释过了。举个例子,这样做是没问题的:

line = r"DEBUG: packetReceived '\x61\x62\x63'"
print re.compile(r"packetReceived '(.*)'").search(line).group(1)

它会打印出 \x61\x62\x63

1

根据你的问题,数据包 等于 '\x61\x62\x63'。它的长度是12个字节,不是15个也不是3个字节。

让你困惑的是,ipython(我知道你在用这个)和Python解释器在显示值的时候使用了 repr() 这个函数,它会试着把值格式化成你代码里的样子。因为在Python字符串常量中,反斜杠是特殊字符,所以 repr() 会把它们显示成重复的样子,就像在Python代码中那样。

这可能对你有帮助:

for char in packet:
    print("%5d %2s %2r" % (ord(char), char, char))

数一数你的字符,看看它们是怎么打印出来的。第一列显示的是字符的序号值,第二列是字符本身,第三列是字符的 repr 表示。

编辑

把最后一行改成:

struct.unpack('BBB', packet)

为:

struct.unpack('BBB', packet.decode('string_escape'))

撰写回答