从混合jascii/ascii文本文件中解析jascii文本



我有一个混合了jascii/shift-jis和ascii文本的文本文件。我正在使用pyparsing,无法对这些字符串进行标记。

下面是一个示例代码:
from pyparsing import *
subrange = r"[x%x40-x%x7ex%x80-x%xFC]"
shiftJisChars = u''.join(srange(subrange % (i,i,i,i)) for i in range(0x81,0x9f+1) + range(0xe0,0xfc+1))
jasciistring = Word(shiftJisChars)
jasciistring.parseString(open('shiftjis.txt').read())

:

<>之前回溯(最近一次调用):文件"test.py",第7行jasciistring.parseString(开放(shiftjis.txt) .read ())文件"C:pythonlibsite-packages pyparse .py",第1100行,在parseString .py中引发exc pyparsing。抛出ParseException之前

文本文件的内容:

<>之前",年代,ˆ ‚‰‚"@‚‰‚"@‚@‚"‚ ‰,ˆ(,Š一番。 ‚‰‚"@‚"‚"‚’‚‰‚ Ž,‡B"之前

(无引号)

当您遇到非ascii字符/字节的问题时,将它们打印到控制台并将其复制/传递到您的问题中是相当没有帮助的。你所看到的往往不是你所得到的。你应该使用内置的repr()函数[Python 3]。x: ascii()]以尽可能明确地显示您的数据。

这样做:

python -c "print repr(open('shiftjis.txt', 'rb').read())"

并将结果复制/粘贴到编辑您的问题。

在等待启示的同时对数据进行逆向工程:Windows代码页必须是一个很好的怀疑对象,cp1252是最常见的。正如@Mark Tolonen所展示的,cp1252几乎符合,只有一个错误。进一步调查表明,其他cp125x编码产生2、3或5个错误。我想只有cp125x编码才会将看起来像逗号的东西(实际上是U+201A SINGLE LOW-9引号)映射到shift-jis前导字节x82。我的结论是,肇事者是cp1252,错误是由于运输过程中的损坏造成的。

另一种可能性是底层的原始编码不是shift-jis,而是它的超集,微软在日文Windows上使用的cp932。然而,有问题的序列'x82@'cp932中也无效。在任何情况下,如果您想要处理的文件来自日文Windows机器,那么使用cp932shift-jis更好。

从你的问题和你的代码中不明显你想做什么,也不知道为什么你想用字节范围来做,而不是把你的数据解码成Unicode。我没有使用pyparsing,但看起来很有可能你喂它的子器官是畸形的。

下面是如何使用正则表达式对输入进行标记的示例。请注意pyparsing语法略有不同(xff而不是Python的' xff')。

代码:

import re, unicodedata
input_bytes = 'x82sx82x88x82x89x82x93@x82x89x82x93@x82@x82x93x82x88x82x89x82x86x82x94[x82x8ax82x89x82x93@x82x93x82x94x82x92x82x89x82x8ex82x87B'
p_ascii = r'[x00-x7f]'
p_hw_katakana = r'[xa1-xdf]' # half-width Katakana
p_jis208 = r'[x81-x9fxe0-xef][x40-x7ex80-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)    'x82x88' U+FF48 FULLWIDTH LATIN SMALL LETTER H
jis208 (4, 6)    'x82x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (6, 8)    'x82x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
ascii  (8, 9)    '@'        U+0040 COMMERCIAL AT
jis208 (9, 11)   'x82x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (11, 13)  'x82x93' 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)  'x82x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
jis208 (18, 20)  'x82x88' U+FF48 FULLWIDTH LATIN SMALL LETTER H
jis208 (20, 22)  'x82x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (22, 24)  'x82x86' U+FF46 FULLWIDTH LATIN SMALL LETTER F
jis208 (24, 26)  'x82x94' U+FF54 FULLWIDTH LATIN SMALL LETTER T
ascii  (26, 27)  '['        U+005B LEFT SQUARE BRACKET
jis208 (27, 29)  'x82x8a' U+FF4A FULLWIDTH LATIN SMALL LETTER J
jis208 (29, 31)  'x82x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (31, 33)  'x82x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
ascii  (33, 34)  '@'        U+0040 COMMERCIAL AT
jis208 (34, 36)  'x82x93' U+FF53 FULLWIDTH LATIN SMALL LETTER S
jis208 (36, 38)  'x82x94' U+FF54 FULLWIDTH LATIN SMALL LETTER T
jis208 (38, 40)  'x82x92' U+FF52 FULLWIDTH LATIN SMALL LETTER R
jis208 (40, 42)  'x82x89' U+FF49 FULLWIDTH LATIN SMALL LETTER I
jis208 (42, 44)  'x82x8e' U+FF4E FULLWIDTH LATIN SMALL LETTER N
jis208 (44, 46)  'x82x87' 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 [a - z]"(a)你的网络太大了(b)你可以很容易地使用UNICODE字符范围而不是字节范围(当然在解码你的数据之后)。

引起我注意的第一件事是您没有以二进制文件的形式打开该文件。我建议使用open('shiftjis.txt', 'rb')这样的代码。您知道该文件包含正常ASCII范围之外的字符,因此通常最好将该文件作为二进制文件打开,然后将其内容解码为Unicode。也许下面这样可以工作(假设'shift-jis'是正确的编解码器名称):

text = open('shiftjis.txt', 'rb').read().decode('shift-jis')
jasciistring.parseString(text)

如果parseString()期望str对象(而不是unicode对象),那么您可以更改最后一行以使用UTF-8编码text:

jasciistring.parseString(text.encode('utf-8'))

我唯一的其他建议是验证jasciistring包含正确的语法;由于您正在使用十六进制范围构建它,因此我希望您需要首先将其视为二进制str,然后将其解码为unicode对象。

您的"文本文件内容"是mojibake(使用错误的编解码器解码文件时显示的垃圾)。我猜错了编解码器,重新编码文本,用ShiftJIS解码,得到:

# coding: utf8
import codecs
s = u'‚s‚ˆ‚‰‚“@‚‰‚“@‚@‚“‚ˆ‚‰‚†‚”[‚Š‚‰‚“@‚“‚”‚’‚‰‚Ž‚‡B'
s = s.encode('cp1252').decode('shift-jis','replace')
print s

输出
This@is@�shift[jis@stringB

所以默认的美国Windows编解码器不太正确:^)

很可能你需要做的就是用shift_jis编解码器读取原始文件:

import codecs
f = codecs.open('shiftjis.txt','rb','shift_jis')
data = f.read()
f.close

data将是包含已解码字符的Unicode字符串。

相关内容

  • 没有找到相关文章

最新更新