当您遇到非 ASCII 字符/字节的问题时,将它们打印到您的控制台并将其复制/粘贴到您的问题中是没有帮助的。你所看到的往往不是你所拥有的。您应该使用内置的 repr() 函数 [Python 3.x: ascii()] 尽可能明确地显示您的数据。
这样做:
python -c "print repr(open('shiftjis.txt', 'rb').read())"
并将结果复制/粘贴到编辑您的问题中。
在等待启发的同时对数据进行逆向工程:Windows 代码页必须是一个很好的嫌疑人,cp1252 是最常见的。正如@Mark Tolonen 所展示的,cp1252 几乎适合,但有一个错误。进一步调查表明,其他cp125x 编码会产生 2、3 或 5 个错误。 AFAIK 只有cp125x 编码会将看起来像逗号的内容(实际上是 U+201A 单低 9 引号)映射到 shift-jis 前导字节\x82。我断定肇事者是cp1252,错误是由于运输途中的损坏造成的。
另一种可能性是底层原始编码不是shift-jis,而是它的超集,即微软在日语Windows上使用的cp932。然而,有问题的序列'\x82@' 在cp932 中也无效。在任何情况下,如果您要处理的文件来自日本 Windows 机器,使用cp932 比使用shift-jis 更好。
从您的问题和代码中,您想要做什么以及为什么要使用字节范围而不是仅仅将您的数据解码为 Unicode 并不明显。我不使用pyparsing,但您提供给它的子范围很可能格式不正确。
以下是如何使用正则表达式标记输入的示例。请注意,pyparsing 语法略有不同(\0xff 而不是 Python 的 `\xff')。
代码:
import re, unicodedata
input_bytes = '\x82s\x82\x88\x82\x89\x82\x93@\x82\x89\x82\x93@\x82@\x82\x93\x82\x88\x82\x89\x82\x86\x82\x94[\x82\x8a\x82\x89\x82\x93@\x82\x93\x82\x94\x82\x92\x82\x89\x82\x8e\x82\x87B'
p_ascii = r'[\x00-\x7f]'
p_hw_katakana = r'[\xa1-\xdf]' # half-width Katakana
p_jis208 = r'[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]'
p_bad = r'.' # anything else
kinds = ['jis208', 'ascii', 'hwk', 'bad']
re_matcher = re.compile("(" + ")|(".join([p_jis208, p_ascii, p_hw_katakana, p_bad]) + ")")
for mobj in re_matcher.finditer(input_bytes):
s = mobj.group()
us = s.decode('shift-jis', 'replace')
print ("%-6s %-9s %-10r U+%04X %s"
% (kinds[mobj.lastindex - 1], mobj.span(), s, ord(us), unicodedata.name(us, '<no name>'))
)
输出:
jis208 (0, 2) '\x82s' U+FF34 FULLWIDTH LATIN CAPITAL LETTER T
jis208 (2, 4) '\x82\x88' U+FF48 FULLWIDTH LATIN SMALL LETTER H
jis208 (4, 6) '\x82\x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (6, 8) '\x82\x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
ascii (8, 9) '@' U+0040 COMMERCIAL AT
jis208 (9, 11) '\x82\x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (11, 13) '\x82\x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
ascii (13, 14) '@' U+0040 COMMERCIAL AT
jis208 (14, 16) '\x82@' U+FFFD REPLACEMENT CHARACTER
jis208 (16, 18) '\x82\x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
jis208 (18, 20) '\x82\x88' U+FF48 FULLWIDTH LATIN SMALL LETTER H
jis208 (20, 22) '\x82\x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (22, 24) '\x82\x86' U+FF46 FULLWIDTH LATIN SMALL LETTER F
jis208 (24, 26) '\x82\x94' U+FF54 FULLWIDTH LATIN SMALL LETTER T
ascii (26, 27) '[' U+005B LEFT SQUARE BRACKET
jis208 (27, 29) '\x82\x8a' U+FF4A FULLWIDTH LATIN SMALL LETTER J
jis208 (29, 31) '\x82\x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (31, 33) '\x82\x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
ascii (33, 34) '@' U+0040 COMMERCIAL AT
jis208 (34, 36) '\x82\x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
jis208 (36, 38) '\x82\x94' U+FF54 FULLWIDTH LATIN SMALL LETTER T
jis208 (38, 40) '\x82\x92' U+FF52 FULLWIDTH LATIN SMALL LETTER R
jis208 (40, 42) '\x82\x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (42, 44) '\x82\x8e' U+FF4E FULLWIDTH LATIN SMALL LETTER N
jis208 (44, 46) '\x82\x87' U+FF47 FULLWIDTH LATIN SMALL LETTER G
ascii (46, 47) 'B' U+0042 LATIN CAPITAL LETTER B
注意 1:您不需要循环并加入 O(N**2) 个字符范围。
如果“jascii”仅表示“FULLWIDTH LATIN (CAPITAL|SMALL) LETTER [AZ]”(a)您的网络太大(b)您可以使用 UNICODE 字符范围而不是 BYTE 范围轻松做到这一点(在课程解码您的数据)。