Обработать эможи как один символ в регулярном выражении
Вот небольшой пример:
reg = ur"((?P<initial>[+\-👍])(?P<rest>.+?))$"
(В обоих случаях файл имеет -*- coding: utf-8 -*-
)
В Python 2:
re.match(reg, u"👍hello").groupdict()
# => {u'initial': u'\ud83d', u'rest': u'\udc4dhello'}
# unicode why must you do this
В то время как в Python 3:
re.match(reg, "👍hello").groupdict()
# => {'initial': '👍', 'rest': 'hello'}
Вышеуказанное поведение на 100% отлично, но переход на Python 3 в настоящее время не является вариантом. Каков наилучший способ репликации 3 результатов в 2, который работает как в узкой, так и в широкой сборке Python? Кажется, что coming приходит ко мне в формате "\ ud83d\udc4d", что делает это сложным.
Ответы
Ответ 1
В узкой сборке Python 2 не BMP-символы являются двумя суррогатными кодовыми точками, поэтому вы не можете правильно использовать их в синтаксисе []
. u'[👍]
эквивалентен u'[\ud83d\udc4d]'
, что означает "match один из \ud83d
или \udc4d
. Пример Python 2.7:
>>> u'\U0001f44d' == u'\ud83d\udc4d' == u'👍'
True
>>> re.findall(u'[👍]',u'👍')
[u'\ud83d', u'\udc4d']
Чтобы исправить как в Python 2, так и в 3, сопоставьте u'👍
OR [+-]
. Это возвращает правильный результат как для Python 2, так и для 3:
#coding:utf8
from __future__ import print_function
import re
# Note the 'ur' syntax is an error in Python 3, so properly
# escape backslashes in the regex if needed. In this case,
# the backslash was unnecessary.
reg = u"((?P<initial>👍|[+-])(?P<rest>.+?))$"
tests = u'👍hello',u'-hello',u'+hello',u'\\hello'
for test in tests:
m = re.match(reg,test)
if m:
print(test,m.groups())
else:
print(test,m)
Выход (Python 2.7):
👍hello (u'\U0001f44dhello', u'\U0001f44d', u'hello')
-hello (u'-hello', u'-', u'hello')
+hello (u'+hello', u'+', u'hello')
\hello None
Выход (Python 3.6):
👍hello ('👍hello', '👍', 'hello')
-hello ('-hello', '-', 'hello')
+hello ('+hello', '+', 'hello')
\hello None
Ответ 2
Просто используйте префикс u
самостоятельно.
В Python 2.7:
>>> reg = u"((?P<initial>[+\-👍])(?P<rest>.+?))$"
>>> re.match(reg, u"👍hello").groupdict()
{'initial': '👍', 'rest': 'hello'}
Ответ 3
Существует один вариант преобразования этого unicode в emoji в python 2.7:
b = dict['vote'] # assign that unicode value to b
print b.decode('unicode-escape')
Я не знаю, что это именно то, что вы точно ищете. Но я думаю, вы можете использовать его, чтобы каким-то образом решить эту проблему.
Ответ 4
Это связано с тем, что Python2 не различает байты и строки Unicode.
Обратите внимание, что интерпретатор Python 2.7 представляет символ как 4 байта. Чтобы получить такое же поведение в Python 3, вам нужно явно преобразовать строку юникода в объект байтов.
# Python 2.7
>>> s = "👍hello"
>>> s
'\xf0\x9f\x91\x8dhello'
# Python 3.5
>>> s = "👍hello"
>>> s
'👍hello'
Итак, для Python 2 просто используйте шестнадцатеричное представление этого символа для шаблона поиска (включая указание длины), и оно работает.
>>> reg = "((?P<initial>[+\-\xf0\x9f\x91\x8d]{4})(?P<rest>.+?))$"
>>> re.match(reg, s).groupdict()
{'initial': '\xf0\x9f\x91\x8d', 'rest': 'hello'}