Не ясно ни из ваших желаемых результатов, ни из вашего кода, что именно вы пытаетесь достичь, но если это просто подсчет слов в отдельных предложениях, тогда стратегия должна быть:
- Считайте
common.txt
в set
для быстрого поиска.
- Прочитайте
sample.txt
и разделите на .
, чтобы получить отдельные предложения.
- Удалите все несловарные символы (вам придется определить их или использовать регулярное выражение
\b
для захвата границ слов) и заменить их пробелами.
- Разделите пробел и посчитайте слова, отсутствующие в
set
из Шаг 1 .
Итак:
import collections
with open("common.txt", "r") as f: # open the `common.txt` for reading
common_words = {l.strip().lower() for l in f} # read each line and and add it to a set
interpunction = ";,'\"" # define word separating characters and create a translation table
trans_table = str.maketrans(interpunction, " " * len(interpunction))
sentences_counter = [] # a list to hold a word count for each sentence
with open("sample.txt", "r") as f: # open the `sample.txt` for reading
# read the whole file to include linebreaks and split on `.` to get individual sentences
sentences = [s for s in f.read().split(".") if s.strip()] # ignore empty sentences
for sentence in sentences: # iterate over each sentence
sentence = sentence.translate(trans_table) # replace the interpunction with spaces
word_counter = collections.defaultdict(int) # a string:int default dict for counting
for word in sentence.split(): # split the sentence and iterate over the words
if word.lower() not in common_words: # count only words not in the common.txt
word_counter[word.lower()] += 1
sentences_counter.append(word_counter) # add the current sentence word count
ПРИМЕЧАНИЕ. В Python 2.x используйте string.maketrans()
вместо str.maketrans()
.
В результате будет получено sentences_counter
, содержащее счетчик слов для каждого из предложений в sample.txt
, где ключ - это фактическое слово, а его ассоциированное значение - это количество слов. Вы можете распечатать результат как:
for i, v in enumerate(sentences_counter):
print("Sentence #{}:".format(i+1))
print("\n".join("\t{}: {}".format(w, c) for w, c in v.items()))
Который будет производить (для ваших данных выборки):
Sentence #1:
area: 1
drainage-basin: 1
great: 1
combined: 1
areas: 1
england: 1
wales: 1
wide: 1
region: 1
fertile: 1
Sentence #2:
mississippi: 1
valley: 1
proper: 1
exceptionally: 1
Имейте в виду, что (английский) язык более сложен, чем этот, например: " Кошка покачивается * , когда * * злится, поэтому держитесь подальше от it ."будет сильно различаться в зависимости от того, как вы относитесь к апострофу. Кроме того, точка не обязательно обозначает конец предложения. Вам следует изучить NLP , если вы хотите провести серьезный лингвистический анализ.
ОБНОВЛЕНИЕ : Хотя я не вижу смысла повторять каждое слово, повторяя данные (количество не будет изменяться в предложении), если вы хотите напечатать каждое слово и вложить все другие показатели ниже, вы можете просто добавить внутренний цикл при печати:
for i, v in enumerate(sentences_counter):
print("Sentence #{}:".format(i+1))
for word, count in v.items():
print("\t{} {}".format(word, count))
print("\n".join("\t\t{}: {}".format(w, c) for w, c in v.items() if w != word))
Что даст вам:
Sentence #1:
area 1
drainage-basin: 1
great: 1
combined: 1
areas: 1
england: 1
wales: 1
wide: 1
region: 1
fertile: 1
drainage-basin 1
area: 1
great: 1
combined: 1
areas: 1
england: 1
wales: 1
wide: 1
region: 1
fertile: 1
great 1
area: 1
drainage-basin: 1
combined: 1
areas: 1
england: 1
wales: 1
wide: 1
region: 1
fertile: 1
combined 1
area: 1
drainage-basin: 1
great: 1
areas: 1
england: 1
wales: 1
wide: 1
region: 1
fertile: 1
areas 1
area: 1
drainage-basin: 1
great: 1
combined: 1
england: 1
wales: 1
wide: 1
region: 1
fertile: 1
england 1
area: 1
drainage-basin: 1
great: 1
combined: 1
areas: 1
wales: 1
wide: 1
region: 1
fertile: 1
wales 1
area: 1
drainage-basin: 1
great: 1
combined: 1
areas: 1
england: 1
wide: 1
region: 1
fertile: 1
wide 1
area: 1
drainage-basin: 1
great: 1
combined: 1
areas: 1
england: 1
wales: 1
region: 1
fertile: 1
region 1
area: 1
drainage-basin: 1
great: 1
combined: 1
areas: 1
england: 1
wales: 1
wide: 1
fertile: 1
fertile 1
area: 1
drainage-basin: 1
great: 1
combined: 1
areas: 1
england: 1
wales: 1
wide: 1
region: 1
Sentence #2:
mississippi 1
valley: 1
proper: 1
exceptionally: 1
valley 1
mississippi: 1
proper: 1
exceptionally: 1
proper 1
mississippi: 1
valley: 1
exceptionally: 1
exceptionally 1
mississippi: 1
valley: 1
proper: 1
Не стесняйтесь убрать печать номера предложения и уменьшите один из отступов табуляции, чтобы получить что-то более желаемое из вашего вопроса. Вы также можете создать древовидный словарь, вместо того, чтобы печатать все в STDOUT, если это больше того, что вам нравится.
ОБНОВЛЕНИЕ 2 : Если вы хотите, вам не нужно использовать set
для common_words
. В этом случае он в значительной степени взаимозаменяем с list
, так что вы можете использовать понимание списка вместо установить понимание (т.е. заменить фигурные квадратные скобки), но просмотр list
операция O(n)
, тогда как поиск set
является операцией O(1)
, и поэтому здесь предпочтительным является set
. Не говоря уже о дополнительном преимуществе автоматической дедупликации, если в common.txt
есть повторяющиеся слова.
Что касается collections.defaultdict()
, то это просто для того, чтобы сэкономить нам немного кодирования / проверки, автоматически инициализируя словарь для ключа всякий раз, когда он запрашивается - без него вам придется делать это вручную:
with open("common.txt", "r") as f: # open the `common.txt` for reading
common_words = {l.strip().lower() for l in f} # read each line and and add it to a set
interpunction = ";,'\"" # define word separating characters and create a translation table
trans_table = str.maketrans(interpunction, " " * len(interpunction))
sentences_counter = [] # a list to hold a word count for each sentence
with open("sample.txt", "r") as f: # open the `sample.txt` for reading
# read the whole file to include linebreaks and split on `.` to get individual sentences
sentences = [s for s in f.read().split(".") if s.strip()] # ignore empty sentences
for sentence in sentences: # iterate over each sentence
sentence = sentence.translate(trans_table) # replace the interpunction with spaces
word_counter = {} # initialize a word counting dictionary
for word in sentence.split(): # split the sentence and iterate over the words
word = word.lower() # turn the word to lowercase
if word not in common_words: # count only words not in the common.txt
word_counter[word] = word_counter.get(word, 0) + 1 # increase the last count
sentences_counter.append(word_counter) # add the current sentence word count
ОБНОВЛЕНИЕ 3 : Если вы просто хотите получить необработанный список слов по всем предложениям, как это выглядит из вашего последнего обновления вопроса, вам даже не нужно рассматривать сами предложения - просто добавьте точку в список связей прочитайте файл построчно, разделите его на пробелы и посчитайте слова как прежде:
import collections
with open("common.txt", "r") as f: # open the `common.txt` for reading
common_words = {l.strip().lower() for l in f} # read each line and and add it to a set
interpunction = ";,'\"." # define word separating characters and create a translation table
trans_table = str.maketrans(interpunction, " " * len(interpunction))
sentences_counter = [] # a list to hold a word count for each sentence
word_counter = collections.defaultdict(int) # a string:int default dict for counting
with open("sample.txt", "r") as f: # open the `sample.txt` for reading
for line in f: # read the file line by line
for word in line.translate(trans_table).split(): # remove interpunction and split
if word.lower() not in common_words: # count only words not in the common.txt
word_counter[word.lower()] += 1 # increase the count
print("\n".join("{}: {}".format(w, c) for w, c in word_counter.items())) # print the counts