Как найти и подсчитать смайлики в строке с помощью 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

проблема, с которой я сталкиваюсь, - это декодирование/кодирование. Я не нашел хорошего варианта для того, как чтобы кодировать / декодировать строку, чтобы я мог правильно найти значки. Пример строки, которую я хочу найти, чтобы найти количество слов и смайликов, выглядит следующим образом:

" смайлик смайлик скалы!enter image description here ты мне нравишьсяenter image description here."

задача: можете ли вы сделать скрипт, который подсчитывает количество слов и смайликов в этой строке? обратите внимание, что смайлики оба сидят рядом со словами без пространства между ними.

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