2017-01-18 12 views
3

У меня возникли трудности с пониманием перевода выражений юникода в их соответствующие символы. Я смотрел спецификацию unicode, и я столкнулся с различными строками, которые отформатированы следующим образом: U+1F600. Насколько я видел, не существует встроенной функции, которая знает, как перевести эти строки в правильное форматирование для Python, например \U0001F600.Представление Unicode для форматирования Unicode?

В моей программе я сделал небольшое регулярное выражение, которое найдет эти шаблоны U\+.{5} и заменит U+ на \U000. Однако я обнаружил, что этот синтаксис не одинаковый для всех символов Юникода, таких как объединение с нулевой шириной, которое фактически должно быть переведено с U+200D на \u200D.

Поскольку я не знаю каждого варианта правильной последовательности escape-кода Unicode, какой метод лучше всего подходит для этого случая? Это то, что есть только конечное количество этих специальных символов, которые я могу просто проверить или полностью ли я об этом не так?

Python версия 2.7.

+0

Извините, я добавлю, что это. Это Python 2.7. :) – lindsay

+0

'u '\ u200D' == u '\ U0000200D'' – ThisSuitIsBlackNot

+0

Спасибо за это! Интересно, добавит ли добавленный пример дополнительный ноль. Если бы это было так, возможно, это могло бы решить неоднородную ошибку. - Оказывается, что это происходит, так как '\ U00001F600' - это другой символ. Спасибо, в любом случае! – lindsay

ответ

3

Я думаю, что ваш самый надежный метод будет разобрать число на целое число, а затем использовать unichr для поиска, что элемент кода:

unichr(0x1f600) # or: unichr(int('1f600', 16)) 

Примечание: на Python 3, это просто chr.

+0

Спасибо за эти ответы. Это может быть я, но я просто попробовал пример Python 2.7, и он вызывает эту ошибку: 'unichr() arg не в диапазоне (0x10000) (узкая сборка Python).' Любые идеи? – lindsay

+0

Что вы получаете для 'import unicodedata; unicodedata.unidata_version'? – wim

+0

Терминал говорит, что я использую '5.2.0'. Возможно, это датировано? – lindsay

0

Вы можете посмотреть в модуле json. Казалось, что это не так просто:

# Unicode escape sequence 
uni = _decode_uXXXX(s, end) 
end += 5 
# Check for surrogate pair on UCS-4 systems 
if sys.maxunicode > 65535 and \ 
0xd800 <= uni <= 0xdbff and s[end:end + 2] == '\\u': 
    uni2 = _decode_uXXXX(s, end + 1) 
    if 0xdc00 <= uni2 <= 0xdfff: 
     uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) 
     end += 6 
char = unichr(uni) 

(от CPython-2.7.9/Lib/JSON/decoder.py линий 129-138)

Я думаю, что было бы проще в использовании json.loads непосредственно:

>>> print json.loads('"\\u0123"') 
ģ 
+0

Если это json, конечно. Но кто сказал что-нибудь о json? – wim

+0

@wim, вы можете создавать строки из последовательностей Unicode и передавать их в json-парсер. – myaut

3

U+NNNN только общее обозначение используется, чтобы говорить о Unicode. Синтаксис Python для одного символа Unicode является одним из:

  • u'\xNN' для символов Unicode через U + 00FF
  • u'\uNNNN' для символов Unicode через U + FFFF
  • u'\U00NNNNNN' для символов Unicode через U + 10FFFF (макс)

Примечание: N - это шестнадцатеричная цифра.

Используйте правильную нотацию при вводе символа. Вы можете использовать более длинные нотации даже для низких символов:

u'A' == u'\x41' == u'\u0041' == u'\U00000041' 

Программным, вы можете также генерировать правильный символ с unichr(n) (Python 2) или chr(n) (Python 3).

Обратите внимание, что перед Python 3.3, были узкие и широкий Unicode сборки Python. unichr/chr может поддерживать только sys.maxunicode, что составляет 65535 (0xFFFF) в узких строках и 1114111 (0x10FFFF) на широких строках. Python 3.3 объединил сборки и решил много проблем с Unicode.

Если вы имеете дело с текстовой строкой в ​​формате U+NNNN, вот регулярное выражение (Python 3). Он ищет U+ и 4-6 шестнадцатеричных цифр и заменяет их версией chr(). Обратите внимание, что символы ASCII (Python 2) или печатные символы (Python 3) будут отображать фактический символ, а не экранированную версию.

>>> re.sub(r'U\+([0-9A-Fa-f]{4,6})',lambda m: chr(int(m.group(1),16)),'testing U+1F600') 
'testing \U0001f600' 
>>> re.sub(r'U\+([0-9A-Fa-f]{4,6})',lambda m: chr(int(m.group(1),16)),'testing U+5000') 
'testing \u5000' 
>>> re.sub(r'U\+([0-9A-Fa-f]{4,6})',lambda m: chr(int(m.group(1),16)),'testing U+0041') 
'testing A' 
>>> re.sub(r'U\+([0-9A-Fa-f]{4,6})',lambda m: chr(int(m.group(1),16)),'testing U+0081') 
'testing \x81' 
+0

O.P. имеет дело с * текстом *, как '' U + 1F600''. Поскольку это не синтаксис Python, есть необходимость в некотором анализе или преобразовании, нет? – wim

+0

Спасибо за эти ответы. Python 3.3 звучит очень хорошо сейчас. Я, вероятно, должен использовать его честно. Я пробовал использовать метод 'unichr' заранее, но это не помогло из-за узкой проблемы сборки. Я предполагаю, что метод Python 3 'chr' может справиться с этой проблемой. – lindsay

+0

Да, как @wim сказал, что я редактирую текстовое выражение символа Юникода. Спасибо за подробный ответ, не считая! :) – lindsay