【问题标题】:Fixing faulty unicode strings修复错误的 unicode 字符串
【发布时间】:2012-12-29 14:07:24
【问题描述】:

错误的 unicode 字符串是其中包含意外编码字节的字符串。 例如:

文本:שלום,Windows-1255 编码:\x99\x8c\x85\x8d,Unicode:u'\u05e9\u05dc\u05d5\u05dd',错误的 Unicode:u'\x99\x8c\x85\x8d'

在解析 MP3 文件中的 ID3 标签时,我有时会碰到这样的字符串。如何修复这些字符串? (例如将u'\x99\x8c\x85\x8d' 转换为u'\u05e9\u05dc\u05d5\u05dd'

【问题讨论】:

    标签: python unicode


    【解决方案1】:

    您可以使用latin-1 编码将u'\x99\x8c\x85\x8d' 转换为'\x99\x8c\x85\x8d'

    In [9]: x = u'\x99\x8c\x85\x8d'
    
    In [10]: x.encode('latin-1')
    Out[10]: '\x99\x8c\x85\x8d'
    

    但是,这似乎不是有效的 Windows-1255 编码字符串。你的意思是'\xf9\xec\xe5\xed'吗?如果是的话,那么

    In [22]: x = u'\xf9\xec\xe5\xed'
    
    In [23]: x.encode('latin-1').decode('cp1255')
    Out[23]: u'\u05e9\u05dc\u05d5\u05dd'
    

    u'\xf9\xec\xe5\xed' 转换为与您发布的所需Unicode 匹配的u'\u05e9\u05dc\u05d5\u05dd'


    如果你真的想将u'\x99\x8c\x85\x8d' 转换为u'\u05e9\u05dc\u05d5\u05dd',那么这恰好可行:

    In [27]: u'\x99\x8c\x85\x8d'.encode('latin-1').decode('cp862')
    Out[27]: u'\u05e9\u05dc\u05d5\u05dd'
    

    上面的编码/解码链是使用这个脚本找到的:

    guess_chain_encodings.py

    """
    Usage example: guess_chain_encodings.py "u'баба'" "u'\xe1\xe0\xe1\xe0'"
    """
    import six
    import argparse
    import binascii
    import zlib
    import utils_string as us
    import ast
    import collections
    import itertools
    import random
    
    encodings = us.all_encodings()
    
    Errors = (IOError, UnicodeEncodeError, UnicodeError, LookupError,
              TypeError, ValueError, binascii.Error, zlib.error)
    
    def breadth_first_search(text, all = False):
        seen = set()
        tasks = collections.deque()
        tasks.append(([], text))
        while tasks:
            encs, text = tasks.popleft()
            for enc, newtext in candidates(text):
                if repr(newtext) not in seen:
                    if not all:
                        seen.add(repr(newtext))
                    newtask = encs+[enc], newtext
                    tasks.append(newtask)
                    yield newtask
    
    def candidates(text):
        f = text.encode if isinstance(text, six.text_type) else text.decode
        results = []
        for enc in encodings:
            try:
                results.append((enc, f(enc)))
            except Errors as err:
                pass
        random.shuffle(results)
        for r in results:
            yield r
    
    def fmt(encs, text):
        encode_decode = itertools.cycle(['encode', 'decode'])
        if not isinstance(text, six.text_type):
            next(encode_decode)
        chain = '.'.join( "{f}('{e}')".format(f = func, e = enc)
                         for enc, func in zip(encs, encode_decode) )
        return '{t!r}.{c}'.format(t = text, c = chain)
    
    def main():
        parser = argparse.ArgumentParser()
        parser.add_argument('start', type = ast.literal_eval, help = 'starting unicode')
        parser.add_argument('stop', type = ast.literal_eval, help = 'ending unicode')
        parser.add_argument('--all', '-a', action = 'store_true')    
        args = parser.parse_args()
        min_len = None
        for encs, text in breadth_first_search(args.start, args.all):
            if min_len is not None and len(encs) > min_len:
                break
            if type(text) == type(args.stop) and text == args.stop:
                print(fmt(encs, args.start))
                min_len = len(encs)
    
    if __name__ == '__main__':
        main()
    

    跑步

    % guess_chain_encodings.py "u'\x99\x8c\x85\x8d'" "u'\u05e9\u05dc\u05d5\u05dd'" --all
    

    产量

    u'\x99\x8c\x85\x8d'.encode('latin_1').decode('cp862')
    u'\x99\x8c\x85\x8d'.encode('charmap').decode('cp862')
    u'\x99\x8c\x85\x8d'.encode('rot_13').decode('cp856')
    

    等等

    【讨论】:

    • 哈哈,我从 python 的解释器中获取了这个值,并且肯定是 windows-1255。哦,好吧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 2018-11-03
    • 2023-03-30
    • 2014-05-20
    • 1970-01-01
    • 2012-04-16
    相关资源
    最近更新 更多