Do czynienia z ciągiem zawierającym wiele kodowania znaków

głosy
9

Nie jestem do końca pewien, jak to pytanie naprawdę, a ja nie mam gdzie blisko do znalezienia odpowiedzi, więc mam nadzieję, że ktoś może mi pomóc.

Piszę aplikację Pythona, który łączy się ze zdalnym serwerem i otrzymuje z powrotem bajt danych, które ja rozpakować za pomocą wbudowanego modułu struct Pythona. Mój problem jest ze strun, ponieważ zawierają wiele kodowania znaków. Oto przykład takiego ciągu znaków:

„^ LThis jest przykładem ^ Gstring z wieloma ^ Jcharacter kodowania”

Gdzie różne kodowania rozpoczyna się i kończy oznaczony jest za pomocą specjalnych znaków ewakuacyjnych:

  • ^ L - Latin1
  • ^ E - Europa Środkowa
  • ^ T - turecki
  • ^ B - Bałtycka
  • ^ J - japoński
  • ^ C - cyrylica
  • ^ G - grecki

I tak dalej ... Potrzebuję sposób przekonwertować tego typu string w Unicode, ale ja naprawdę nie wiem, jak to zrobić. Czytałem się na kodekach Pythona i string.encode / dekodowania, ale jestem naprawdę nikt mądrzejszy. Należy wspomnieć także, że nie mam kontroli nad jak struny są wyprowadzane przez gospodarza.

Mam nadzieję, że ktoś może mi pomóc jak zacząć na ten temat.

Utwórz 13/10/2008 o 15:26
źródło użytkownik
W innych językach...                            


5 odpowiedzi

głosy
7

Oto stosunkowo prosty przykład jak to zrobić ...

# -*- coding: utf-8 -*-
import re

# Test Data
ENCODING_RAW_DATA = (
    ('latin_1',    'L', u'Hello'),        # Latin 1
    ('iso8859_2',  'E', u'dobrý večer'),  # Central Europe
    ('iso8859_9',  'T', u'İyi akşamlar'), # Turkish
    ('iso8859_13', 'B', u'Į sveikatą!'),  # Baltic
    ('shift_jis',  'J', u'今日は'),        # Japanese
    ('iso8859_5',  'C', u'Здравствуйте'), # Cyrillic
    ('iso8859_7',  'G', u'Γειά σου'),   # Greek
)

CODE_TO_ENCODING = dict([(chr(ord(code)-64), encoding) for encoding, code, text in ENCODING_RAW_DATA])
EXPECTED_RESULT = u''.join([line[2] for line in ENCODING_RAW_DATA])
ENCODED_DATA = ''.join([chr(ord(code)-64) + text.encode(encoding) for encoding, code, text in ENCODING_RAW_DATA])

FIND_RE = re.compile('[\x00-\x1A][^\x00-\x1A]*')

def decode_single(bytes):
    return bytes[1:].decode(CODE_TO_ENCODING[bytes[0]])

result = u''.join([decode_single(bytes) for bytes in FIND_RE.findall(ENCODED_DATA)])

assert result==EXPECTED_RESULT, u"Expected %s, but got %s" % (EXPECTED_RESULT, result)
Odpowiedział 13/10/2008 o 16:29
źródło użytkownik

głosy
4

Nie ma wbudowaną funkcjonalność do dekodowania ciąg tak, ponieważ jest to naprawdę własny niestandardowy kodek. Wystarczy podzielić ciąg na tych znaków sterujących i dekoduje go odpowiednio.

Oto (bardzo wolno) Przykładem takiej funkcji, która obsługuje latin1 i Shift-JIS:

latin1 = "latin-1"
japanese = "Shift-JIS"

control_l = "\x0c"
control_j = "\n"

encodingMap = {
    control_l: latin1,
    control_j: japanese}

def funkyDecode(s, initialCodec=latin1):
    output = u""
    accum = ""
    currentCodec = initialCodec
    for ch in s:
        if ch in encodingMap:
            output += accum.decode(currentCodec)
            currentCodec = encodingMap[ch]
            accum = ""
        else:
            accum += ch
    output += accum.decode(currentCodec)
    return output

Szybsza wersja może korzystać str.split lub wyrażeń regularnych.

(Także, jak widać w tym przykładzie, „^ J” jest znak kontrolny dla „nowej linii”, więc dane wejściowe będzie miał jakieś ciekawe ograniczeń).

Odpowiedział 13/10/2008 o 15:52
źródło użytkownik

głosy
3

Chciałbym napisać, że kodek stopniowo zeskanowany i dekodowane ciąg bajtów jak przyszli razem. Zasadniczo trzeba by oddzielić ciągi na kawałki ze spójnego kodowania i dekodowania tych i dołączyć je do strun, która im towarzyszyła.

Odpowiedział 13/10/2008 o 15:32
źródło użytkownik

głosy
2

Na pewno trzeba podzielić ciąg najpierw do podciągów wih różnych kodowania i dekodowania każdego z nich oddzielnie. Tylko dla zabawy, obowiązkowy „jedna linia” wersja:

import re

encs = {
    'L': 'latin1',
    'G': 'iso8859-7',
    ...
}

decoded = ''.join(substr[2:].decode(encs[substr[1]])
             for substr in re.findall('\^[%s][^^]*' % ''.join(encs.keys()), st))

(Sprawdzanie żadnego błędu, a także będziemy chcieli zdecydować, w jaki sposób obsłużyć „^” znaków podciągi)

Odpowiedział 13/10/2008 o 16:24
źródło użytkownik

głosy
1

Pewnie nie masz jakikolwiek sposób przekonać osobę, która gospodarze drugą maszynę, aby przełączyć na Unicode?

Jest to jeden z powodów, dla Unicode zostało wymyślone, po wszystkim.

Odpowiedział 13/10/2008 o 15:55
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more