2012-12-29 29 views
5

Chuỗi unicode bị lỗi là chuỗi đã vô tình mã hóa các byte trong đó. Ví dụ:Sửa các chuỗi unicode bị lỗi

Text: שלום, Windows-1255-mã hóa: \x99\x8c\x85\x8d, Unicode: u'\u05e9\u05dc\u05d5\u05dd', Lỗi Unicode: u'\x99\x8c\x85\x8d'

đôi khi tôi va vào dây như vậy khi phân tích các thẻ ID3 trong file MP3. Làm thế nào tôi có thể sửa các chuỗi này? (Ví dụ chuyển đổi u'\x99\x8c\x85\x8d' vào u'\u05e9\u05dc\u05d5\u05dd')

Trả lời

10

Bạn có thể chuyển đổi u'\x99\x8c\x85\x8d'-'\x99\x8c\x85\x8d' bằng cách sử dụng mã hóa latin-1:

In [9]: x = u'\x99\x8c\x85\x8d' 

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

Tuy nhiên, nó có vẻ như đây không phải là một chuỗi hợp lệ Windows-1255-mã hóa. Có phải bạn có nghĩa là '\xf9\xec\xe5\xed'? Nếu có, thì

In [22]: x = u'\xf9\xec\xe5\xed' 

In [23]: x.encode('latin-1').decode('cp1255') 
Out[23]: u'\u05e9\u05dc\u05d5\u05dd' 

chuyển đổi u'\xf9\xec\xe5\xed' thành u'\u05e9\u05dc\u05d5\u05dd' khớp với mã unicode bạn muốn.


Nếu bạn thực sự muốn chuyển đổi u'\x99\x8c\x85\x8d' vào u'\u05e9\u05dc\u05d5\u05dd', sau đó điều này xảy ra để làm việc:

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

Chuỗi mã hóa/giải mã trên đã được tìm thấy sử dụng kịch bản này:

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

Chạy

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

mang

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

, vv

+1

lol'd tại rot_13 –

+0

haha, tôi lấy giá trị này từ thông dịch viên python, và đã tích cực đó là 'Windows- 1255'. ồ. – iTayb

Các vấn đề liên quan