unicode_escape
не працює взагалі
Виявляється, що string_escape
або unicode_escape
рішення не працює взагалі - особливо, воно не працює за наявності фактичного Unicode.
Якщо ви можете бути впевнені, що будь -який символ , який не є ASCII, буде уникнути (і пам’ятайте, що все, що перебуває за межами перших 128 символів, не є ASCII), unicode_escape
зробить правильно для вас. Але якщо в рядку вже є будь-які буквальні символи, що не належать до ASCII, все піде не так.
unicode_escape
принципово розроблений для перетворення байтів у текст Unicode. Але в багатьох місцях - наприклад, вихідний код Python - вихідні дані - це вже текст Unicode.
Єдиний спосіб, як це може працювати правильно, це, якщо спочатку кодувати текст у байтах. UTF-8 - це розумне кодування для всього тексту, так що це має працювати, правда?
Наступні приклади наведені в Python 3, так що літеральні рядки є більш чистими, але однакова проблема існує і з дещо різними проявами як на Python 2, так і на 3.
>>> s = 'naïve \\t test'
>>> print(s.encode('utf-8').decode('unicode_escape'))
naïve test
Ну, це неправильно.
Новий рекомендований спосіб використання кодеків, які розшифровують текст у текст, - це codecs.decode
прямий дзвінок . Чи допомагає це?
>>> import codecs
>>> print(codecs.decode(s, 'unicode_escape'))
naïve test
Зовсім ні. (Крім того, вище є UnicodeError на Python 2.)
unicode_escape
Кодек, незважаючи на свою назву, виявляється, припустити , що все не-ASCII байти в кодуванні Latin-1 (ISO-8859-1). Тож вам доведеться зробити це так:
>>> print(s.encode('latin-1').decode('unicode_escape'))
naïve test
Але це жахливо. Це обмежує вас 256 символами Latin-1, як ніби Unicode взагалі ніколи не був винайдений!
>>> print('Ernő \\t Rubik'.encode('latin-1').decode('unicode_escape'))
UnicodeEncodeError: 'latin-1' codec can't encode character '\u0151'
in position 3: ordinal not in range(256)
Додавання регулярного виразу для вирішення проблеми
(Дивно, але зараз у нас немає двох проблем.)
Що нам потрібно зробити, це застосувати unicode_escape
декодер лише до тих речей, які, напевно, є текстом ASCII. Зокрема, ми можемо переконатися, що застосуємо його лише до дійсних послідовностей втечі Python, які гарантовано є текстом ASCII.
План полягає в тому, що ми знайдемо послідовності втечі, використовуючи регулярний вираз, і будемо використовувати функцію в якості аргументу, re.sub
щоб замінити їх на значення, яке не визначається.
import re
import codecs
ESCAPE_SEQUENCE_RE = re.compile(r'''
( \\U........ # 8-digit hex escapes
| \\u.... # 4-digit hex escapes
| \\x.. # 2-digit hex escapes
| \\[0-7]{1,3} # Octal escapes
| \\N\{[^}]+\} # Unicode characters by name
| \\[\\'"abfnrtv] # Single-character escapes
)''', re.UNICODE | re.VERBOSE)
def decode_escapes(s):
def decode_match(match):
return codecs.decode(match.group(0), 'unicode-escape')
return ESCAPE_SEQUENCE_RE.sub(decode_match, s)
І з цим:
>>> print(decode_escapes('Ernő \\t Rubik'))
Ernő Rubik
'spam'+"eggs"+'''some'''+"""more"""
обробляти рядок, що містить ?