3

我掉进了unicode地狱。

我的环境在 unix,python 2.7.3

LC_CTYPE=zh_TW.UTF-8
LANG=en_US.UTF-8

我正在尝试以人类可读格式转储十六进制编码数据,这是简化的代码

#! /usr/bin/env python
# encoding:utf-8
import sys

s=u"readable\n"  # previous result keep in unicode string
s2="fb is not \xfb"  # data read from binary file
s += s2

print s   # method 1
print s.encode('utf-8')  # method 2
print s.encode('utf-8','ignore')  # method 3
print s.decode('iso8859-1')  # method 4

# method 1-4 display following error message
#UnicodeDecodeError: 'ascii' codec can't decode byte 0xfb 
# in position 0: ordinal not in range(128)

f = open('out.txt','wb')
f.write(s)

我只想打印出 0xfb。

我应该在这里描述更多。关键是's += s2'。where s 将保留我之前解码的字符串。s2 是下一个应该附加到 s 中的字符串。

如果我修改如下,它会发生在写文件上。

s=u"readable\n"
s2="fb is not \xfb"
s += s2.decode('cp437')
print s
f=open('out.txt','wb')
f.write(s)
# UnicodeEncodeError: 'ascii' codec can't encode character
# u'\u221a' in position 1: ordinal not in range(128)

我希望 out.txt 的结果是

readable
fb is not \xfb

或者

readable
fb is not 0xfb

[解决方案]

#! /usr/bin/env python
# encoding:utf-8
import sys
import binascii

def fmtstr(s):
    r = ''
    for c in s:
        if ord(c) > 128:
            r = ''.join([r, "\\x"+binascii.hexlify(c)])
        else:
            r = ''.join([r, c])
    return r

s=u"readable"
s2="fb is not \xfb"
s += fmtstr(s2)
print s
f=open('out.txt','wb')
f.write(s)
4

1 回答 1

3

我强烈怀疑您的代码实际上在上一行出错了:那个s += s2。s2 只是一系列字节,不能任意附加到 unicode 对象(而是一系列代码点)。

如果您打算将 '\xfb' 表示为U+FB, LATIN SMALL LETTER U WITH CIRCUMFLEX,则最好像这样分配它:

s2 = u"\u00fb"

但是您说您只想打印出控制字符的 \xHH 代码。如果您只是希望它成为人类可以理解的东西,并且仍然可以明显看出字符串中的特殊字符,那么repr可能就足够了。首先,不要s是 unicode 对象,因为您在这里将字符串视为一系列字节,而不是一系列代码点。

s = s.encode('utf-8')
s += s2

print repr(s)

最后,如果您不希望在外部repr添加额外的引号,以进行漂亮的打印或其他任何事情,那么在 Python(我知道)中没有简单的内置方法可以做到这一点。我以前用过这样的东西:

import re
controlchars_re = re.compile(r'[\x00-\x31\x7f-\xff]')

def _show_control_chars(match):
    txt = repr(match.group(0))
    return txt[1:-1]

def escape_special_characters(s):
    return controlchars_re.sub(_show_control_chars, s.replace('\\', '\\\\'))

您可以很容易地调整controlchars_re正则表达式来定义您关心转义的字符。

于 2012-05-10T02:33:00.053 回答