Разница между двумя реализациями Gson с неизменяемыми

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, находятся в латинском-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-текстом. В частности, мы можем убедиться, что применим только к действительным escape-последовательностям Python, которые гарантированно будут ASCII-текстом.

План состоит в том, что мы найдем escape-последовательности, используя регулярное выражение, и используем как аргумент 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
0
задан hatellla 17 January 2019 в 18:01
поделиться