2012-12-29 13 views
5

Nieprawidłowy ciąg znaków Unicode to taki, który przypadkowo zakodował w nim bajty. Na przykład:Naprawianie uszkodzonych ciągów Unicode

Tekst: שלום, Windows-1255 zakodowane: \x99\x8c\x85\x8d, Unicode: u'\u05e9\u05dc\u05d5\u05dd', Uszkodzony Unicode: u'\x99\x8c\x85\x8d'

czasami wpadać takich strun podczas analizowania tagi ID3 w plikach MP3. Jak mogę naprawić te łańcuchy? (Np konwertować u'\x99\x8c\x85\x8d' do u'\u05e9\u05dc\u05d5\u05dd')

Odpowiedz

10

Można konwertować u'\x99\x8c\x85\x8d' do '\x99\x8c\x85\x8d' użyciem kodującego latin-1:

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

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

Jednak wydaje się, że to nie jest ważne Windows 1255 zakodowany ciąg. Czy miałeś na myśli '\xf9\xec\xe5\xed'? Jeśli tak, to

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

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

konwertuje u'\xf9\xec\xe5\xed' do u'\u05e9\u05dc\u05d5\u05dd' który odpowiada żądanej unicode zostanie zaksięgowana.


Jeśli naprawdę chcesz przekonwertować u'\x99\x8c\x85\x8d' do u'\u05e9\u05dc\u05d5\u05dd', to zdarza się działać:

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

Powyższy łańcuch kodowania/dekodowania stwierdzono za pomocą tego skryptu:

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

Running

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

daje

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

itp

+1

lol'd na rot_13 –

+0

haha, wziąłem tę wartość z interpretera Pythona i był przekonany, że było 'Windows- 1255'. No cóż. – iTayb

Powiązane problemy