9

この質問を実際にどのように行うべきか正確にはわかりません。また、答えを見つけるにはほど遠いので、誰かが私を助けてくれることを願っています.

リモート ホストに接続し、バイト データを受信する Python アプリを作成しています。このデータは、Python の組み込み struct モジュールを使用して解凍します。文字列には複数の文字エンコーディングが含まれているため、私の問題は文字列にあります。このような文字列の例を次に示します。

"^Lこれは、複数の ^Jcharacter エンコーディングを持つ ^Gstring の例です"

異なるエンコーディングが開始および終了する場所は、特別なエスケープ文字を使用してマークされます。

  • ^L - ラテン語 1
  • ^E - 中央ヨーロッパ
  • ^T - トルコ語
  • ^B - バルト海
  • ^J - 日本語
  • ^C - キリル文字
  • ^G - ギリシャ語

などなど... この種の文字列を Unicode に変換する方法が必要ですが、その方法が本当にわかりません。私は Python のコーデックと string.encode/decode について調べましたが、実際にはそれほど賢明ではありません。また、ホストによって文字列がどのように出力されるかを制御できないことにも言及する必要があります。

誰かがこれを始める方法を手伝ってくれることを願っています。

4

5 に答える 5

7

これは、それを行う方法の比較的簡単な例です...

# -*- 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)
于 2008-10-13T15:29:10.557 に答える
4

このような文字列をデコードするための組み込み機能はありません。これは実際には独自のカスタム コーデックであるためです。これらの制御文字で文字列を分割し、それに応じてデコードするだけです。

latin1 と 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

より高速なバージョンでは、str.split または正規表現を使用する場合があります。

(また、この例でわかるように、「^J」は「改行」の制御文字であるため、入力データにはいくつかの興味深い制限があります。)

于 2008-10-13T14:52:14.907 に答える
3

文字列をインクリメンタルにスキャンし、バイトが出現するたびにデコードするコーデックを作成します。基本的に、一貫したエンコーディングで文字列をチャンクに分割し、それらをデコードして、それに続く文字列に追加する必要があります。

于 2008-10-13T14:32:48.970 に答える
2

最初に文字列を異なるエンコーディングの部分文字列に分割し、それぞれを個別にデコードする必要があります。楽しみのために、必須の「1行」バージョン:

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))

(エラーチェックはありません。また、部分文字列内の '^' 文字の処理方法を決定する必要があります)

于 2008-10-13T15:24:45.543 に答える
1

他のマシンをホストしている人に Unicode に切り替えるよう説得する方法はないと思いますか?

結局のところ、これが Unicode が発明された理由の 1 つです。

于 2008-10-13T14:55:31.810 に答える