9

我不确定如何真正问这个问题,而且我离找到答案还很遥远,所以我希望有人能帮助我。

我正在编写一个 Python 应用程序,它连接到远程主机并接收返回的字节数据,我使用 Python 的内置 struct 模块对其进行解包。我的问题是字符串,因为它们包含多个字符编码。以下是此类字符串的示例:

"^L这是一个示例 ^Gstring 具有多个 ^J 字符编码"

使用特殊转义字符标记不同编码开始和结束的位置:

  • ^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

您必须首先将字符串拆分为具有不同编码的子字符串,然后分别解码每个子字符串。只是为了好玩,强制性的“单行”版本:

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 的原因之一。

于 2008-10-13T14:55:31.810 回答