удалить эмодзи unicode, используя re в python

Я попытался удалить смайлики из текста твита Unicode и распечатать результат в python 2.7, используя

myre = re.compile(u'[\u1F300-\u1F5FF\u1F600-\u1F64F\u1F680-\u1F6FF\u2600-\u26FF\u2700-\u27BF]+',re.UNICODE)
print myre.sub('', text)

но кажется почти все символы удалены из текста. Я проверил несколько ответов из других сообщений, к сожалению, ни один из них здесь не работает. Я сделал что-то не так в re.compile()?

вот пример вывода, что все символы были удалены:

“   '   //./” ! # # # …

person Young    schedule 26.10.2014    source источник
comment
Это Питон 2? Python можно построить с широкой или узкой поддержкой Unicode; у вас, вероятно, есть сборка UCS-2, а не UCS-4, и это влияет на то, что вы можете делать с регулярными выражениями.   -  person Martijn Pieters    schedule 26.10.2014
comment
И, пожалуйста, дайте нам образец ввода.   -  person Martijn Pieters    schedule 26.10.2014
comment
Мне удалось воспроизвести вашу проблему, и я также увидел, что сборка UCS-2 все равно выдает исключение при попытке скомпилировать выражение, так что здесь проблема не в этом.   -  person Martijn Pieters    schedule 26.10.2014
comment
u'\u1f300' должно быть u'\U0001f300'. Первый - '\u1f30' и '0'.   -  person Mark Tolonen    schedule 26.10.2014


Ответы (1)


Вы используете неправильное обозначение для точек юникода, отличных от BMP; вы хотите использовать \U0001FFFF, заглавную U и 8 цифр:

myre = re.compile(u'['
    u'\U0001F300-\U0001F5FF'
    u'\U0001F600-\U0001F64F'
    u'\U0001F680-\U0001F6FF'
    u'\u2600-\u26FF\u2700-\u27BF]+', 
    re.UNICODE)

Это можно сократить до:

myre = re.compile(u'['
    u'\U0001F300-\U0001F64F'
    u'\U0001F680-\U0001F6FF'
    u'\u2600-\u26FF\u2700-\u27BF]+', 
    re.UNICODE)

поскольку ваши первые два диапазона являются смежными.

В вашей версии указывалось (с добавленными пробелами для удобства чтения):

[\u1F30 0-\u1F5F F\u1F60 0-\u1F64 F\u1F68 0-\u1F6F F \u2600-\u26FF\u2700-\u27BF]+

Это потому, что escape-последовательность \uxxxx всегда занимает только 4 шестнадцатеричных цифры, а не 5.

Самый большой из этих диапазонов — 0-\u1F6F (то есть от цифры 0 до ), который охватывает < em>очень большой диапазон стандарта Unicode.

Исправленное выражение работает, если вы используете исполняемый файл Python для UCS-4:

>>> import re
>>> myre = re.compile(u'['
...     u'\U0001F300-\U0001F64F'
...     u'\U0001F680-\U0001F6FF'
...     u'\u2600-\u26FF\u2700-\u27BF]+', 
...     re.UNICODE)
>>> myre.sub('', u'Some example text with a sleepy face: \U0001f62a')
u'Some example text with a sleepy face: '

Эквивалент UCS-2:

myre = re.compile(u'('
    u'\ud83c[\udf00-\udfff]|'
    u'\ud83d[\udc00-\ude4f\ude80-\udeff]|'
    u'[\u2600-\u26FF\u2700-\u27BF])+', 
    re.UNICODE)

Вы можете объединить их в свой скрипт с обработчиком исключений:

try:
    # Wide UCS-4 build
    myre = re.compile(u'['
        u'\U0001F300-\U0001F64F'
        u'\U0001F680-\U0001F6FF'
        u'\u2600-\u26FF\u2700-\u27BF]+', 
        re.UNICODE)
except re.error:
    # Narrow UCS-2 build
    myre = re.compile(u'('
        u'\ud83c[\udf00-\udfff]|'
        u'\ud83d[\udc00-\ude4f\ude80-\udeff]|'
        u'[\u2600-\u26FF\u2700-\u27BF])+', 
        re.UNICODE)

Конечно, регулярное выражение уже устарело, поскольку оно не распространяется на эмодзи, определенные в более новых версиях Unicode; кажется, что он охватывает эмодзи, определенные до Unicode 8.0 (поскольку U+1F91D HANDSHAKE был добавлен в Unicode 9.0).

Если вам нужно более современное регулярное выражение, возьмите его из пакета, который активно пытается идти в ногу со временем. -дата на эмодзи; он специально поддерживает создание такого регулярного выражения:

import emoji

def remove_emoji(text):
    return emoji.get_emoji_regexp().sub(u'', text)

Пакет в настоящее время актуален для Unicode 11.0 и имеет инфраструктуру для быстрого обновления до будущих выпусков. Все, что нужно сделать вашему проекту, — это обновить его, когда появится новая версия.

person Martijn Pieters    schedule 26.10.2014
comment
Как раз то, что я комментировал выше, но я получаю sre_constants.error: bad character range на узкой сборке Python 2. - person Mark Tolonen; 26.10.2014
comment
@MarkTolonen: да, вы можете использовать это только в широкой сборке, см. Python, преобразовать 4-байтовый символ, чтобы избежать ошибки MySQL. Неверное строковое значение: для подхода (вместо этого вам придется сопоставлять суррогатные пары UTF-16). - person Martijn Pieters; 26.10.2014
comment
@MarkTolonen: добавлена ​​версия UCS-2. - person Martijn Pieters; 26.10.2014
comment
Вот почему я использую Python 3.3+ :) - person Mark Tolonen; 26.10.2014
comment
Вау, спасибо! Кажется, сборка USC-4 работает правильно! Мне лучше узнать больше об USC и юникоде. Меня интересует одна вещь: u'[' и ➿]. Почему здесь есть цитата [', но нет цитаты после ➿? - person Young; 26.10.2014
comment
@Young Я просто разбил выражение на несколько строк, чтобы сделать его читаемым. Все, что вы видите, это несколько строковых литералов Unicode (u'...') в строке, которые Python объединяет для вас в одну строку. - person Martijn Pieters; 26.10.2014
comment
@MartijnPieters Я не понимал, почему заглавная буква U и 8 цифр являются правильным обозначением для точек юникода, отличных от BMP. Когда бы я использовал это по сравнению с 4-значным обозначением. Можете ли вы демистифицировать это, пожалуйста? - person Ankur Agarwal; 22.10.2015
comment
@abc: BMP использует кодовые точки до 0xFFFF. Это четыре цифры. Во всем, кроме BMP, используется больше четырех шестнадцатеричных цифр, поэтому для них нельзя использовать \uhhhh 4-значный синтаксис, вместо этого необходимо использовать \Uhhhhhhhh 8-значный синтаксис. - person Martijn Pieters; 22.10.2015
comment
@MartijnPieters Спасибо, Мартейн - person Ankur Agarwal; 23.10.2015
comment
Хороший! Чтобы преобразовать строку в юникод в функции, я сделал lambda txt : myre.sub("", unicode(txt, "utf-8")), и это сработало без проблем. Спасибо. - person Marcelo Lazaroni; 08.11.2016