2013-11-13 2 views
3

Скажем, у вас есть строкаКакой способ конвертировать в Юникод?

s = "C:\Users\Eric\Desktop\beeline.txt" 

, который вы хотите переместить в Unicode, если это не так.

return s if PY3 or type(s) is unicode else unicode(s, "unicode_escape") 

Если есть шанс, что строка будет иметь \ U (т.е. каталог пользователя), и вы, вероятно, получите ошибки декодирования Unicode.

UnicodeDecodeError: 'unicodeescape' codec can't decode bytes in position 3-4: truncated \UXXXXXXXX escape 

Что случилось с просто заставить его выглядеть примерно так:

return s if PY3 or type(s) is unicode else unicode(s.encode('string-escape'), "unicode_escape") 

Или явно проверка на наличие \ U ок, как это единственный угловой случай?

Я хочу, чтобы код будет работать на обоих питона 2 & 3.

+0

Вы можете использовать сырые литералов здесь: 's = г «C: \ Users \ Eric \ Desktop \ beeline.txt» ' – georg

+0

Обязательно четко продумайте, что делать с входом типа' s = r 'C: \ Users \ Eric \ Desktop \ pr \ U000000eat- \ U000000e0-портер "'. – Alfe

ответ

0

Он отлично работает с английским, но, столкнувшись с реальным, например юникода, то forcable перевод не может использовать ту же кодировку, как это было бы на по умолчанию, оставляя вас с неприятными ошибками.

Я обернул свой данный код в функции под названием assert_unicode (заменило это с isinstance) и провели тест на текст на иврите (который просто говорит «привет»), проверить это:

In [1]: def assert_unicode(s): 
      return s if isinstance(s, unicode) else unicode(s, 'unicode_escape')  

In [2]: assert_unicode(u'שלום') 
Out[2]: u'\u05e9\u05dc\u05d5\u05dd' 

In [3]: assert_unicode('שלום') 
Out[3]: u'\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d' 

Ты видишь? оба возвращают объект unicode, но все еще есть большая разница. И если вы попробуете распечатать или работать со вторым примером, это, вероятно, потерпит неудачу (простой пример печати не удался для меня, и я использую console2, который очень дружелюбен к юникоду).

Решение этого вопроса? использование utf-8. Это стандарт в эти дни, и если вы убедитесь, что все будет рассматриваться как UTF-8, а также, он должен работать как шарм для любого данного языка:

In [4]: def assert_unicode(s): 
      return s if isinstance(s, unicode) else unicode(s, 'utf-8')  

In [5]: assert_unicode(u'שלום') 
Out[5]: u'\u05e9\u05dc\u05d5\u05dd' 

In [6]: assert_unicode('שלום') 
Out[6]: u'\u05e9\u05dc\u05d5\u05dd' 
+0

Отлично. Благодарю. Я думаю, что «unicode_escape» в документах python отбросил меня. Мне интересно, что он будет использовать сейчас. – Alex

0

Ниже процедура аналогична по духу ответ by @yuvi, но он проходит через несколько кодировок (настраивается) и возвращает используемую кодировку. Он также обрабатывает ошибки (проходящие только преобразование вещей, которые basestring) более изящно.

#unicode practice, this routine forces stringish objects to unicode 
#preferring utf-8 but works through other encodings on error 
#return values are the encoded string and the encoding used 
def to_unicode_or_bust_multile_encodings(obj, encoding=['utf-8','latin-1','Windows-1252']): 
    'noencoding' 
    successfullyEncoded = False 
    for elem in encoding: 
    if isinstance(obj, basestring): 
     if not isinstance(obj, unicode): 
     try: 
      obj = unicode(obj, elem) 
      successfullyEncoded = True 
      #if we succeed then exit early 
      break 
     except: 
      #encoding did not work, try the next one 
      pass 

    if successfullyEncoded: 
    return obj, elem 
    else: 
    return obj,'no_encoding_found' 
0

Что такое правильный способ для преобразования в юникод?

Здесь:

unicode_string = bytes_object.decode(character_encoding) 

Теперь возникает вопрос: У меня есть последовательность байтов, какая кодировка символов я должен использовать, чтобы преобразовать их в строку Unicode?

Ответ зависит от того, откуда берутся байты.

В вашем случае, bytestring указывается с использованием литерала Python для байтов (Python 2), поэтому кодировка представляет собой кодировку символов вашего исходного файла Python. Если в верхней части файла нет объявления кодировки символов (комментарий выглядит так: # -*- coding: utf-8 -*-), то исходная кодировка по умолчанию: 'ascii' на Python 2 ('utf-8' - Python 3).Таким образом, ответ в вашем случае:

if isinstance(s, str) and not PY3: 
    return s.decode('ascii') 

Или вы могли бы использовать литералы Unicode непосредственно (Python 2 и Python 3.3+):

unicode_string = u"C:\\Users\\Eric\\Desktop\\beeline.txt" 
+0

Возможно, мне следовало спросить: «Каков правильный способ конвертировать в Юникод, если вы не знаете, каким будет источник?». (строка примера из файла конфигурации, поэтому я не могу использовать литералы напрямую, и я бы хотел, чтобы это запускалось независимо от версии ОС или Python) – Alex

+0

@Alex: кто пишет файл конфигурации? Что мешает вам сохранить его с помощью известной кодировки символов (например, '' utf-8'')? Неважно, что такое ОС или версия Python. – jfs

+0

любой случайный пользователь мог редактировать файл конфигурации, используя любой редактор. – Alex

Смежные вопросы