python 正则表达式在字符串编码上无效

1 投票
1 回答
2794 浏览
提问于 2025-04-17 18:42

我有一个字符串(g),我用一个简单的正则表达式来找里面的数字。问题是,这个正则表达式在这个字符串类型上似乎不管用(可能是编码的问题?)。不过,"正常"的字符串是可以的。请问我漏掉了什么?下面是我在代码环境中看到的步骤:

(这个例子是一个在线扑克比赛的总结)

不管用:

>>> g
'F\x00u\x00l\x00l\x00 \x00T\x00i\x00l\x00t\x00 \x00P\x00o\x00k\x00e\x00r\x00 \x00T\x00o\x00u\x00r\x00n\x00a\x00m\x00e\x00n\x00t\x00 \x00S\x00u\x00m\x00m\x00a\x00r\x00y\x00 \x00$\x002\x00.\x002\x005\x00 \x00H\x00e\x00a\x00d\x00s\x00-\x00U\x00p\x00 \x00S\x00i\x00t\x00 \x00&\x00 \x00G\x00o\x00 \x00(\x002\x005\x000\x005\x005\x005\x009\x001\x004\x00)\x00 \x002\x00-\x007\x00 \x00T\x00r\x00i\x00p\x00l\x00e\x00 \x00D\x00r\x00a\x00w\x00 \x00L\x00i\x00m\x00i\x00t\x00 \x00(\x00T\x00u\x00r\x00b\x00o\x00,\x00 \x00H\x00e\x00a\x00d\x00s\x00 \x00U\x00p\x00)\x00\n\x00B\x00u\x00y\x00-\x00I\x00n\x00:\x00 \x00$\x002\x00.\x001\x002\x00 \x00+\x00 \x00$\x000\x00.\x001\x003\x00\n\x00B\x00u\x00y\x00-\x00I\x00n\x00 \x00C\x00h\x00i\x00p\x00s\x00:\x00 \x001\x005\x000\x000\x00\n\x002\x00 \x00E\x00n\x00t\x00r\x00i\x00e\x00s\x00\n\x00T\x00o\x00t\x00a\x00l\x00 \x00P\x00r\x00i\x00z\x00e\x00 \x00P\x00o\x00o\x00l\x00:\x00 \x00$\x004\x00.\x002\x004\x00\n\x00T\x00o\x00u\x00r\x00n\x00a\x00m\x00e\x00n\x00t\x00 \x00s\x00t\x00a\x00r\x00t\x00e\x00d\x00:\x00 \x002\x000\x001\x003\x00/\x000\x003\x00/\x000\x008\x00 \x000\x006\x00:\x000\x000\x00:\x002\x007\x00 \x00E\x00T\x00\n\x00T\x00o\x00u\x00r\x00n\x00a\x00m\x00e\x00n\x00t\x00 \x00f\x00i\x00n\x00i\x00s\x00h\x00e\x00d\x00:\x00 \x002\x000\x001\x003\x00/\x000\x003\x00/\x000\x008\x00 \x000\x006\x00:\x001\x004\x00:\x003\x000\x00 \x00E\x00T\x00\n\x00\n\x001\x00:\x00 \x00A\x00n\x00d\x00r\x00e\x00y\x003\x003\x001\x000\x00,\x00 \x00$\x004\x00.\x002\x004\x00\n\x002\x00:\x00 \x00s\x00y\x00n\x00t\x00h\x00e\x00s\x00i\x00i\x00s\x00\n\x00s\x00y\x00n\x00t\x00h\x00e\x00s\x00i\x00i\x00s\x00 \x00f\x00i\x00n\x00i\x00s\x00h\x00e\x00d\x00 \x00i\x00n\x00 \x002\x00n\x00d\x00 \x00p\x00l\x00a\x00c\x00e'
>>> myre = re.compile(u"""\(([0-9]+)\)""",re.UNICODE)
>>> m = myre.search(g)
>>> m.groups()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'

能管用:

>>> g="Full Tilt Poker Tournament Summary $2.25 Heads-Up Sit & Go (250555914) 2-7 Triple Draw Limit (Turbo, Heads Up)"
>>> m = myre.search(g)
>>> m.groups()
('250555914',)

1 个回答

4

你有一些用UTF-16编码的数据,但没有字节顺序标记(BOM)。在尝试匹配正则表达式之前,先把它解码成Unicode:

>>> g[:-1].decode('utf-16-le')
u'Full Tilt Poker Tournament Summary $2.25 Heads-Up Sit & Go (250555914) 2-7 Triple Draw Limit (Turbo, Heads Up)\nBuy-In: $2.12 + $0.13\nBuy-In Chips: 1500\n2 Entries\nTotal Prize Pool: $4.24\nTournament started: 2013/03/08 06:00:27 ET\nTournament finished: 2013/03/08 06:14:30 ET\n\n1: Andrey3310, $4.24\n2: synthesiis\nsynthesiis finished in 2nd plac'
>>> myre.search(g[:-1].decode('utf-16-le')).groups()
(u'250555914',)

不过,我需要把最后一个字节去掉才能解码,因为最后缺少了一个空字节。如果你发现数据的末尾缺失,那么你很可能在开头也缺少了一些数据,BOM就是放在开头的。BOM的作用是告诉解码器使用的是哪种UTF-16编码方式(小端或大端),如果没有这个标记,我们就需要明确告诉Python用小端来解码。

如果你解码的是完整的数据,包括BOM,那么你可以直接使用.decode('utf-16')来解码。

如果你是从文件中读取这些数据,建议使用codecs.open(),这样Python会帮你自动解码成Unicode:

import codecs

for line in codecs.open('filename.txt', 'r', encoding='utf16'):
    # handle line

因为如果不这样做,像.readlines()这样的操作会在字节级别上分割换行符,而在UTF-16中,换行符也是用两个字节来编码的。

撰写回答