2013-10-03 1 views
9

Эта тема была адресована для текстовых смайликов по адресу link1, link2, link3. Тем не менее, я хотел бы сделать что-то немного отличное от соответствия простым смайликам. Я сортирую твиты, содержащие значки смайликов. Следующая информация в Юникоде содержит только такие смайлики: pdf.Как найти и считать смайлики в строке с помощью python?

Использование строки с английскими словами, которая также содержит любые из этих смайликов от pdf, я хотел бы иметь возможность сравнить количество смайликов с количеством слов.

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

$cat <file containing the strings with emoticons> | ./emo.py 

emo.py псевдо сценария:

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 

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

«Smiley emoticon rocks! enter image description here Мне нравятся вы enter image description here."

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

+0

Использует regexp требование здесь? – abarnert

+0

Это все довольно обычное регулярное выражение, так что ... прочитали ли вы [Регулярное выражение HOWTO] (http://docs.python.org/3.3/howto/regex.html#regex-howto), или, что лучше, третье -партийный учебник? – abarnert

ответ

14

Во-первых, здесь нет необходимости кодировать. У вас есть строка Unicode, а механизм re может обрабатывать Unicode, поэтому просто используйте его.

A character class может включать в себя ряд символов, указав первый и последний дефис между ними. И вы можете указать символы Unicode, которые вы не знаете, как вводить с помощью escape-последовательностей \U. Итак:

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 до U+FFFF. Невозможно найти эти символы, но это нормально, потому что их не существует для поиска; вы можете просто предположить, что они не существуют, если вы получаете ошибку «недопустимый диапазон», компилируя регулярное выражение.

За исключением, конечно, что есть хороший шанс, что там, где вы получаете фактические строки из, они UTF-16-BE или UTF-16-LE, так что символы сделать существуют, они» re просто закодированы в суррогатные пары. И вы хотите совместить эти суррогатные пары, верно? Поэтому вам нужно перевести поиск в поиск суррогатной пары. То есть, конвертировать высокие и низкие точки кода в суррогатных паре кодовых единиц, затем (с точки зрения 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.

Если это не так очевидно, как это выражается в регулярном выражении, вот пример для диапазона [\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) 
+0

Мне пришлось изменить ваш r 'на u' как re.findall (u '[\ U0001f600- \ U0001f650]', s.decode ('utf-8')), который затем правильно находит смайлики. Спасибо @abarnert! – blehman

+0

@simplyclimb: Да, вам нужно 'u '...'', а переменная 's' должна _also_ быть строкой unicode. (По какой-то причине я предположил, что вы используете Python 3, но, глядя на вопрос, это, очевидно, 2.x.) Но вы все еще хотите 'r'. В этом случае отбрасывание этого происходит неважно, потому что литерал python stirng интерпретирует escape-последовательность '\ U0001f600' точно так же, как и механизм' re' ... Но это хорошая идея всегда использовать необработанные строки для регулярных выражений, если только у вас есть определенная причина не в том, чтобы вместо изучения каждого регулярного выражения выяснить, нужна ли вам необработанная строка или нет. – abarnert

+1

Re 'ur '[\ U0001f600- \ U0001f650]' 'не удается скомпилировать на некоторых строках Python меньше 3,3 (я думаю, что узкие сборки - то есть' sys.maxunicode == 0xffff') с ошибкой «неправильный диапазон символов» , –

0

Если вы пытаетесь читать символы юникода за пределами диапазона ascii, не конвертируйте в диапазон ascii. Просто оставьте его как юникода и работать оттуда (непроверенные):

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 

не лучшее решение, но оно должно работать.

Смежные вопросы