2013-03-19 4 views
1

В Python 2.7, учитывая эту строку:Подсчет вхождения нескольких строк в другой строке

Пятна является коричневой собакой. Пятно имеет коричневые волосы. Волосы пятна коричневые.

Что было бы лучшим способом найти сумму «Спот», «коричневые» и «волосы» в строке? В этом примере оно вернется 8.

Я ищу что-то вроде string.count("Spot","brown","hair"), но работает с «строками, которые будут найдены» в кортеже или списке.

Спасибо!

+0

Вы хотите сосчитать "hair" в "hairy"? Ответ nltk не учитывает его, в то время как ответы 'count()' и регулярных выражений выполняются. – EOL

+0

Это легко исключить с помощью 'regex' путем добавления границ слов (' \ b'). – mgilson

+0

Действительно, но это меняет ваш ответ. :) – EOL

ответ

8

Это делает то, о чем вы просили, но обратите внимание, что оно также будет считать слова как "волосатый", "Браунер" и т.д.

>>> s = "Spot is a brown dog. Spot has brown hair. The hair of Spot is brown." 
>>> sum(s.count(x) for x in ("Spot", "brown", "hair")) 
8 

Вы можете также записать его как map

>>> sum(map(s.count, ("Spot", "brown", "hair"))) 
8 

более надежное решение может использовать nltk package

>>> import nltk # Natural Language Toolkit 
>>> from collections import Counter 
>>> sum(x in {"Spot", "brown", "hair"} for x in nltk.wordpunct_tokenize(s)) 
8 
+0

Я собирался добавить это в свой ответ. О, хорошо ... +1 – mgilson

+0

Я не собирался ничего говорить о nltk, так как я не знаю этого пакета - я бы добавил +1 для этого, если мог. – mgilson

+0

+1 для опции nltk, которая не учитывает «волосы» в «волосатых» - в этом случае это то, что хочет исходный плакат. – EOL

3

я мог бы использовать Counter:

s = 'Spot is a brown dog. Spot has brown hair. The hair of Spot is brown.' 
words_we_want = ("Spot","brown","hair") 
from collections import Counter 
data = Counter(s.split()) 
print (sum(data[word] for word in words_we_want)) 

Обратите внимание, что это будет под кол на 1, так как 'brown.' и 'brown' отдельные элементы счетчика.

Несколько менее элегантное решение, которое не споткнуться на пунктуации использует регулярное выражение:

>>> len(re.findall('Spot|brown|hair','Spot is a brown dog. Spot has brown hair. The hair of Spot is brown.')) 
8 

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

'|'.join(re.escape(x) for x in words_we_want) 

Хорошая вещь об этих решений заключается в том, что они имеют гораздо лучшую алгоритмическую сложность по сравнению с решением gnibbler. Конечно, на самом деле, что действительно лучше работает с данными реального мира, все еще необходимо измерять OP (поскольку OP является единственным с данными реального мира)

+1

И я полагаю, что с регулярным выражением вы могли бы лениво оценить это с помощью 're.finditer' + старого ожидания' sum (1 for _ in ...) 'idiom. – mgilson

+0

+1 для 'finditer()' и регулярных выражений вообще: они быстры, для больших строк и количества возможных слов. – EOL

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