3

私はユニコード地獄に落ちています。

UNIX、Python 2.7.3 の私の環境

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

16 進数でエンコードされたデータを人間が読める形式でダンプしようとしています。ここに簡略化されたコードがあります

#! /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' です。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+FBLATIN SMALL LETTER U WITH CIRCUMFLEX代わりに次のように割り当てたほうがよいでしょう。

s2 = u"\u00fb"

しかし、制御文字の \xHH コードを出力したいだけだとおっしゃいました。人間が理解できるものにしたいだけで、特殊文字が文字列に含まれていることが明らかになれば、それでrepr十分かもしれません。まず、sUnicode オブジェクトにする必要はありません。これは、ここで文字列を一連のコード ポイントではなく、一連のバイトとして扱っているためです。

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 に答える