python delimiter分隔符用法_Python:使用十六进制分隔符分割字节

我正在使用几个二进制文件,我想解析存在的UTF-8字符串。

我目前有一个函数,它接受一个文件的起始位置,然后返回找到的字符串:

1

2

3

4

5

6def str_extract(file, start, size, delimiter = None, index = None):

file.seek(start)

if (delimiter != None and index != None):

return file.read(size).explode('0x00000000')[index] #incorrect

else:

return file.read(size)

文件中的一些字符串用0x00 00 00 00分隔,是否有可能像PHP的爆炸那样拆分它们? 我是Python的新手,所以欢迎任何有关代码改进的指针。

样本文件:

48 00 65 00 6C 00 6C 00 6F 00 20 00 57 00 6F 00 72 00 6C 00 64 00 | 00 00 00 00 | 31 00 32 00 33 00是Hello World123,我注意到00 00 00 00分隔符用|条围住它。

所以:

1str_extract(file, 0x00, 0x20, 0x00000000, 0) => 'Hello World'

同理:

1str_extract(file, 0x00, 0x20, 0x00000000, 1) => '123'

split是PHP explode的等效函数。 您是基于实际的0x00000000字符串进行拆分还是在检查文件中的实际零字节?

@figs检查4个零的实际序列。 我举了一个例子来说明我的观点。

那么文件中的|字符是什么?

它们实际上并不在我的文件中,只是用于指示一系列零的可读性管道。

这是在Python 2还是Python 3中?

Python 2,但我认为我不怕学习3解决方案。

我将假设你在这里使用Python 2,但是编写代码来处理Python 2和Python 3。

您有UTF-16数据,而不是UTF-8。您可以将其读作二进制数据,并使用str.split()方法拆分四个NUL字节:

1file.read(size).split(b'\x00' * 4)[index]

生成的数据被编码为UTF-16 little-endian(您可能在开始时省略或未省略UTF-16 BOM;您可以使用以下方法解码数据:

1result.decode('utf-16-le')

然而,这将失败,因为我们只是在最后一个NUL字节切断了文本; Python在找到的前4个NUL上进行拆分,并且不会跳过作为文本一部分的最后一个NUL字节。

更好的想法是首先解码为Unicode,然后拆分Unicode双NUL代码点:

1file.read(size).decode('utf-16-le').split(u'\x00' * 2)[index]

把它作为一个函数放在一起将是:

1

2

3

4

5

6

7

8

9

10def str_extract(file, start, size, delimiter = None, index = None):

file.seek(start)

if (delimiter is not None and index is not None):

delimiter = delimiter.decode('utf-16-le') # or pass in Unicode

return file.read(size).decode('utf-16-le').split(delimiter)[index]

else:

return file.read(size).decode('utf-16-le')

with open('filename', 'rb') as fobj:

result = str_extract(fobj, 0, 0x20, b'\x00' * 4, 0)

如果文件在开始时作为BOM,请考虑将文件打开为UTF-16而不是以:

1

2

3

4import io

with io.open('filename', 'r', encoding='utf16') as fobj:

# ....

并删除显式解码。

Python 2演示:

1

2

3

4

5

6

7>>> from io import BytesIO

>>> data = b'H\x00e\x00l\x00l\x00o\x00 \x00W\x00o\x00r\x00l\x00d\x00\x00\x00\x00\x001\x002\x003\x00'

>>> fobj = BytesIO(data)

>>> str_extract(fobj, 0, 0x20, '\x00' * 4, 0)

u'Hello World'

>>> str_extract(fobj, 0, 0x20, '\x00' * 4, 1)

u'123'

现在阅读BOM,我该如何检测到这一点?我更喜欢这种方式,因为它比显式解码更干净。

@VeraWang:你的文件将以字节FF FE开头(编码U + FEFF ZERO WIDTH NO-BREAK SPACE到UTF-16 little-endian)。

对不起,这里有另一个问题:这些文件包含英文,德文,法文,日文的字符,还可以包含字符串中没有的内容。 Python是否具有这些字符集的预定十六进制范围?如果有意义,我只想要"可读"字符。

@VeraWang:不,那没有多大意义。 :-)你的意思是你想过滤可打印的字符?标签,换行符,不间断空格等都带有意义,你必须更加具体。

是的,抱歉这是漫长的一天:-)。还包括空字节。

@VeraWang:你可以使用str.translate()来有效地删除某些代码点; result.translate({0: None})告诉方法将0代码点(NUL)映射到None,这意味着删除它。

@VeraWang:或者,让字典(其键必须是整数,表示Unicode代码点)映射到其他代码点(所以也是一个整数,但单个Unicode字符也可以),以用其他代码点替换代码点。所以result.translate({0: u?})会用问号替换NUL字符。

谢谢,我已经从这篇文章中学到了很多关于Python的知识!

首先,您需要以二进制模式打开文件。

然后你split str(或bytes,依赖于Python的版本),分隔符为四个零字节b'\0\0\0\0':

1

2

3

4

5

6def str_extract(file, start, size, delimiter = None, index = None):

file.seek(start)

if (delimiter is not None and index is not None):

return file.read(size).split(delimiter)[index]

else:

return file.read(size)

此外,您需要处理编码,因为str_extract只返回二进制数据,而您的测试数据是UTF-16小端,如Martijn Pieters所说:

1

2>>> str_extract(file, 0x00, 0x20, b'\0\0\0\0', 0).decode('utf-16-le')

u'Hello World'

此外:用is not None测试变量不是None。

不完全Hello World;更像是H\x00e\x00l\x00l\x00o\x00 \x00W\x00o\x00r\x00l\x00d,这是UTF-16小端数据。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值