Pyparsing - анализ текста jascii из смешанного текстового файла jascii / ascii? - PullRequest
4 голосов
/ 04 мая 2011

У меня есть текстовый файл со смешанным текстом jascii / shift-jis и ascii. Я использую pyparsing и не могу токенизировать такие строки.

Вот пример кода:

from pyparsing import *

subrange = r"[\0x%x40-\0x%x7e\0x%x80-\0x%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())

Я получаю:

Traceback (most recent call last):
  File "test.py", line 7, in 
    jasciistring.parseString(open('shiftjis.txt').read())
  File "C:\python\lib\site-packages\pyparsing.py", line 1100, in parseString
    raise exc pyparsing.ParseException

Содержимое текстового файла:

"‚s‚ˆ‚‰‚“@‚‰‚“@‚@‚“‚ˆ‚‰‚†‚”[‚Š‚‰‚“@‚“‚”‚’‚‰‚Ž‚‡B"

(без кавычек)

Ответы [ 3 ]

1 голос
/ 15 мая 2011

Если у вас есть проблема с символами / байтами, отличными от 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 ОДНОКРАТНАЯ МАРКА ЦИТАТЫ U + 201A), на ведущий байт shift-jis \x82. Я пришел к выводу, что нарушитель cp1252, и что ошибка вызвана повреждением при транспортировке.

Другая возможность состоит в том, что исходная кодировка не shift-jis, а ее расширенный набор cp932 от Microsoft, используемый в японской Windows. Однако проблемная последовательность '\x82@' недопустима в cp932. В любом случае, если файл (-ы), которые вы хотите обработать, были получены с японского компьютера с Windows, лучше использовать cp932, чем shift-jis.

Из вашего вопроса и вашего кода не очевидно, что вы хотите делать, и почему вы хотите делать это с байтовыми диапазонами, а не просто декодировать свои данные в Unicode. Я не использую pyparsing, но весьма вероятно, что поддиапазоны, которыми вы его кормите, имеют неправильные формы.

Ниже приведен пример того, как вы можете токенизировать свой ввод, используя регулярные выражения. Обратите внимание, что синтаксический синтаксический анализ немного отличается (\0xff вместо `\ xff 'в Python).

Код:

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» означает «ПИСЬМО ПОЛНОЙ ШИРИНЫ (КАПИТАЛ | МАЛЕНЬКИЙ) [AZ]» (a) ваша сеть слишком велика (b) вы можете легко это сделать, используя диапазоны символов UNICODE вместо диапазонов BYTE (после конечно расшифровываю ваши данные).

0 голосов
/ 15 мая 2011

У вас "содержимое текстового файла" равно 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, содержащей декодированные символы.

0 голосов
/ 15 мая 2011

Первое, что бросается в глаза, это то, что вы не открываете файл как двоичный файл. Я рекомендую использовать код вроде open('shiftjis.txt', 'rb'). Вы знаете, что файл содержит символы вне нормального диапазона ASCII, поэтому обычно лучше открыть файл в виде двоичного файла, а затем декодировать содержимое в Unicode. Возможно, что-то подобное будет работать (при условии, что 'shift-jis' - правильное имя кодека):

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

Если parseString() ожидает объект str (в отличие от объекта unicode), вы можете изменить последнюю строку для кодирования text, используя UTF-8:

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

Единственная другая рекомендация, которую я имею, состоит в том, чтобы проверить, что jasciistring содержит правильную грамматику; поскольку вы создаете его с использованием шестнадцатеричных диапазонов, я ожидаю, что вам нужно сначала обработать его как двоичный файл str, а затем декодировать его в unicode объект.

...