Python – количество слов вхождения

Я пытаюсь сделать функцию, позволяющую найти количество вхождений (целых) слов (нечувствительных к регистру) в тексте.

Пример :

>>> text = """Antoine is my name and I like python. Oh ! your name is antoine? And you like Python! Yes is is true, I like PYTHON and his name__ is John O'connor""" assert( 2 == Occs("Antoine", text) ) assert( 2 == Occs("ANTOINE", text) ) assert( 0 == Occs("antoin", text) ) assert( 1 == Occs("true", text) ) assert( 0 == Occs("connor", text) ) assert( 1 == Occs("you like Python", text) ) assert( 1 == Occs("Name", text) ) 

Вот основная попытка:

 def Occs(word,text): return text.lower().count(word.lower()) 

Этот не работает, потому что он не основан на словах.
Эта функция должна быть быстрой, текст может быть очень большой.

Должен ли я разбить его на массив?
Есть ли простой способ сделать эту функцию?

Изменить (python 2.3.4)

    5 Solutions collect form web for “Python – количество слов вхождения”

     from collections import Counter import re Counter(re.findall(r"\w+", text)) 

    или, для версии без учета регистра

     Counter(w.lower() for w in re.findall(r"\w+", text)) 

    В Python <2.7 используйте defaultdict вместо Counter :

     freq = defaultdict(int) for w in re.findall(r"\w+", text): freq[w.lower()] += 1 

    Вот непифонный способ – я предполагаю, что это вопрос домашней работы в любом случае …

     def count(word, text): result = 0 text = text.lower() word = word.lower() index = text.find(word, 0) while index >= 0: result += 1 index = text.find(word, index) return result 

    Конечно, для действительно больших файлов это будет медленным в основном из-за text.lower() . Но вы всегда можете придумать нечувствительный к регистру find и исправить это!

    Почему я сделал это так? Потому что я думаю, что он фиксирует то, что вы пытаетесь сделать лучше всего: пройдите text , считая, сколько раз вы находите в нем word .

    Кроме того, эти методы решают некоторые неприятные проблемы с пунктуацией: split оставит их там, и вы не будете соответствовать тогда, не так ли?

    Спасибо за помощь.
    Вот мое решение:

     import re starte = "(?<![az])((?<!')|(?<=''))" ende = "(?![az])((?!')|(?=''))" def NumberOfOccurencesOfWordInText(word, text): """Returns the nb. of occurences of whole word(s) (case insensitive) in a text""" pattern = (re.match('[az]', word, re.I) != None) * starte\ + word\ + (re.match('[az]', word[-1], re.I) != None) * ende return len(re.findall(pattern, text, re.IGNORECASE)) 

    См. Этот вопрос .

    Одна из реализаций заключается в том, что если ваш файл ориентирован на линию, то чтение его по очереди и использование простой split() в каждой строке не будет очень дорогостоящим. Это, конечно, предполагает, что слова не охватывают разрывы строк, так или иначе (без дефис).

    Мне была дана точно такая же проблема, чтобы решить эту проблему, поэтому я много размышлял над этой проблемой. Вот почему я решил поделиться своим решением здесь. Хотя мое решение требует времени для выполнения, но внутреннее время обработки немного лучше, чем findall, я думаю. Я могу быть не прав. В любом случае здесь идет решение:

     def CountOccurencesInText(word,text): """Number of occurences of word (case insensitive) in text""" acceptedChar = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '-', ' ') for x in ",!?;_\n«»():\".": if x == "\n" or x == "«" or x == "»" or x == "(" or x == ")" or x == "\"" or x == ":" or x == ".": text = text.replace(x," ") else: text = text.replace(x,"") """this specifically handles the imput I am attaching my cv to this e-mail.""" if len(word) == 32: for x in ".": word = word.replace(x," ") punc_Removed_Text = "" text = text.lower() for i in range(len(text)): if text[i] in acceptedChar: punc_Removed_Text = punc_Removed_Text + text[i] """"this specifically handles the imput: Do I have to take that as a 'yes'""" elif text[i] == '\'' and text[i-1] == 's': punc_Removed_Text = punc_Removed_Text + text[i] elif text[i] == '\'' and text[i-1] in acceptedChar and text[i+1] in acceptedChar: punc_Removed_Text = punc_Removed_Text + text[i] elif text[i] == '\'' and text[i-1] == " " and text[i+1] in acceptedChar: punc_Removed_Text = punc_Removed_Text + text[i] elif text[i] == '\'' and text[i-1] in acceptedChar and text[i+1] == " " : punc_Removed_Text = punc_Removed_Text + text[i] frequency = 0 splitedText = punc_Removed_Text.split(word.lower()) for y in range(0,len(splitedText)-1,1): element = splitedText[y] if len(element) == 0: if(splitedText[y+1][0] == " "): frequency += 1 elif len(element) == 0: if(len(splitedText[y+1][0])==0): frequency += 1 elif len(splitedText[y+1]) == 0: if(element[len(element)-1] == " "): frequency += 1 elif (element[len(element)-1] == " " and splitedText[y+1][0] == " "): frequency += 1 return frequency 

    И вот профиль:

     128006 function calls in 7.831 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 7.831 7.831 :0(exec) 32800 0.062 0.000 0.062 0.000 :0(len) 11200 0.047 0.000 0.047 0.000 :0(lower) 1 0.000 0.000 0.000 0.000 :0(print) 72800 0.359 0.000 0.359 0.000 :0(replace) 1 0.000 0.000 0.000 0.000 :0(setprofile) 5600 0.078 0.000 0.078 0.000 :0(split) 1 0.000 0.000 7.831 7.831 <string>:1(<module>) 1 0.000 0.000 7.831 7.831 ideone-gg.py:225(doit) 5600 7.285 0.001 7.831 0.001 ideone-gg.py:3(CountOccurencesInText) 1 0.000 0.000 7.831 7.831 profile:0(doit()) 0 0.000 0.000 profile:0(profiler) 
    Python - лучший язык программирования в мире.