Как найти и подсчитать смайлики в строке с помощью python?
эта тема была адресована для текстовых смайликов на link1 и, link2, link3. Тем не менее, я хотел бы сделать что-то немного отличное от сопоставления простых смайликов. Я сортирую твиты, которые содержат значки смайликов. Следующая информация unicode содержит именно такие смайлики:pdf.
использование строки с английскими словами, которая также содержит любой из этих смайликов из pdf, Я хотел бы иметь возможность сравнить количество смайликов с количеством слов.
направление, в котором я направлялся вниз, не кажется лучшим вариантом, и я искал некоторую помощь. Как вы можете видеть в сценарии ниже, я просто планировал выполнить работу из командной строки:
$cat <file containing the strings with emoticons> | ./emo.py
emo.py сценарий psuedo:
import re
import sys
for row in sys.stdin:
print row.decode('utf-8').encode("ascii","replace")
#insert regex to find the emoticons
if match:
#do some counting using .split(" ")
#print the counting
проблема, с которой я сталкиваюсь, - это декодирование/кодирование. Я не нашел хорошего варианта для того, как чтобы кодировать / декодировать строку, чтобы я мог правильно найти значки. Пример строки, которую я хочу найти, чтобы найти количество слов и смайликов, выглядит следующим образом:
" смайлик смайлик скалы! ты мне нравишься."
задача: можете ли вы сделать скрипт, который подсчитывает количество слов и смайликов в этой строке? обратите внимание, что смайлики оба сидят рядом со словами без пространства между ними.
3 ответов
во-первых, нет необходимости кодировать здесь на всех. У вас есть строка Unicode и re
engine может обрабатывать Unicode, поэтому просто используйте его.
A класс персонажа может включать в себя диапазон символов, указав первый и последний с дефисом между ними. И вы можете указать символы Юникода, которые вы не знаете, как ввести с \U
escape-последовательности. Итак:
import re
s=u"Smiley emoticon rocks!\U0001f600 I like you.\U0001f601"
count = len(re.findall(ru'[\U0001f600-\U0001f650]', s))
или, если строка достаточно большая, что создание целого findall
список выглядит расточительством:
emoticons = re.finditer(ru'[\U0001f600-\U0001f650]', s)
count = sum(1 for _ in emoticons)
подсчет слов, вы можете сделать отдельно:
wordcount = len(s.split())
если вы хотите сделать все сразу, вы можете использовать группу чередование:
word_and_emoticon_count = len(re.findall(ru'\w+|[\U0001f600-\U0001f650]', s))
как указывает @strangefeatures, версии Python до 3.3 разрешают сборки "узкого Unicode". И, например, большинство сборок CPython Windows являются узкими. В узких сборках символы могут находиться только в диапазоне U+0000
to U+FFFF
. Нет способа найти их. символы, но это нормально, потому что они не существуют для поиска; вы можете просто предположить, что они не существуют, если вы получаете ошибку "недопустимый диапазон", компилируя регулярное выражение.
за исключением, конечно, того, что есть хороший шанс, что где бы вы ни получали свои фактические строки, они UTF-16-BE или UTF-16-LE, поэтому символы do существуют, они просто закодированы в суррогатные пары. И ты хочешь подойти к этим суррогатным парам, верно? Поэтому вам нужно перевести свой поиск в поисках суррогатной пары. То есть преобразуйте свои высокие и низкие кодовые точки в суррогатные пары кодовых единиц, а затем (в терминах Python) найдите:
(lead == low_lead and lead != high_lead and low_trail <= trail <= DFFF or
lead == high_lead and lead != low_lead and DC00 <= trail <= high_trail or
low_lead < lead < high_lead and DC00 <= trail <= DFFF)
вы можете оставить второе условие в последнем случае, если вы не беспокоитесь о принятии фиктивного UTF-16.
если не очевидно, как это переводится в regexp, вот пример для диапазона [\U0001e050-\U0001fbbf]
в UTF-16-BE:
(\ud838[\udc50-\udfff])|([\ud839-\ud83d].)|(\ud83e[\udc00-\udfbf])
конечно, если ваш диапазон достаточно мал, что low_lead == high_lead
этот становится проще. Например, диапазон исходного вопроса можно искать с помощью:
\ud83d[\ude00-\ude50]
один последний трюк, если вы на самом деле не знаете, собираетесь ли вы получить UTF-16-LE или UTF-16-BE (и спецификация находится далеко от данных, которые вы ищете): потому что никакой суррогатный ведущий или следовой код не действителен как отдельный символ или как другой конец пары, вы можете просто искать в обоих направлениях:
(\ud838[\udc50-\udfff])|([\ud839-\ud83d][\udc00-\udfff])|(\ud83e[\udc00-\udfbf])|
([\udc50-\udfff]\ud838)|([\udc00-\udfff][\ud839-\ud83d])|([\udc00-\udfbf]\ud83e)
Если вы пытаетесь прочитать символы юникода вне диапазона ascii, не преобразуйте на диапазон ascii. Просто оставьте его как unicode и работайте оттуда (непроверенный):
import sys
count = 0
emoticons = set(range(int('1f600',16), int('1f650', 16)))
for row in sys.stdin:
for char in row:
if ord(char) in emoticons:
count += 1
print "%d emoticons found" % count
Не лучшее решение, но оно должно работать.
мое решение включает в себя emoji
и regex
модули. Модуль regex поддерживает распознавание кластеров графем (последовательностей кодовых точек Unicode, отображаемых как один символ), поэтому мы можем считать emojis как один раз, хотя он состоит из 4 emojis.
import emoji
import regex
def split_count(text):
emoji_counter = 0
data = regex.findall(r'\X', text)
for word in data:
if any(char in emoji.UNICODE_EMOJI for char in word):
emoji_counter += 1
# Remove from the given text the emojis
text = text.replace(word, '')
words_counter = len(text.split())
return emoji_counter, words_counter
тестирование:
line = "hello emoji hello how are you today"
counter = split_count(line)
print("Number of emojis - {}, number of words - {}".format(counter[0], counter[1]))
выход:
Number of emojis - 5, number of words - 7