Итак, я пытаюсь найти одну или несколько строк в каждой строке файла и подсчитать, сколько раз каждая строка появляется в файле. В некоторых строках есть только одна из строк, однако в других строках может быть несколько целевых строк, если это имеет смысл. Я пытаюсь использовать регулярное выражение для этого.
Итак, я пробовал следующее (уже прочитав файл и разделив его на строки с помощью .readlines):
1count=0
2count=0
3count=0
Pattern=r'(?i)(\bString1\b)|(\bString2\b)|(\bString3\b)'
i=0
while i!=len(lines)
match=re.search(pattern, lines[i])
if match:
if match.group(1):
1count=1count+1
elif match.group(2):
2count=2count+1
elif match.group(3):
3count=3count+1
i=i+1
Это работает, когда в строке нет нескольких совпадений, однако, когда они есть, очевидно, учитывается только первое совпадение, а затем движется дальше. Есть ли способ просканировать всю строку? Я знаю, что re.findall находит все совпадения, но затем помещает их в массив, и я не знаю, как надежно подсчитать количество совпадений для каждого слова, поскольку совпадения в findall будут иметь разные индексы в массиве каждый Переберите.
Вы можете использовать findall
и подсчитывать вхождения в конце.
Например:
import re
count1=0
count2=0
count3=0
data = "String1 String2 String2 String3\nString1 String1\nString3"
Pattern=r'(?i)(\bString1\b)|(\bString2\b)|(\bString3\b)'
lines = data.split('\n')
all_matches = []
i = 0
while i!=len(lines):
match=re.findall(Pattern, lines[i])
all_matches.extend(match)
i += 1
count1 = len([el for el in all_matches if el[0] == 'String1'])
count2 = len([el for el in all_matches if el[1] == 'String2'])
count3 = len([el for el in all_matches if el[2] == 'String3'])
print(count1, count2, count3)
Примечание. findall
вернет список кортежей, где первый элемент кортежа соответствует первой группе и так далее.
all_matches
будет список кортежей, каждый кортеж имеет форму (matched item for string1, matched item for string2, matched item for string3)
если нет совпадения, то будет ''
,что-то вроде того:
[('String1', '', ''), ('', 'String2', ''), ('', 'String2', ''), ...]
Например, при вычислении count1
мы создаем список элементов, которые соответствуют String1 (условие здесь, как мы видели, первый элемент кортежа равен «String1») следующим образом:
first_group = [el for el in all_matches if el[0] == 'String1']
затем мы возвращаем его длину как значение count1length этих элементов:
count1 = len(first_group)
Не могли бы вы немного подробнее объяснить, что происходит в самом конце, с count=len([el for el in all_matches if el[0] == 'String1']) , пожалуйста? Я почти понял, но я все еще новичок в программировании, поэтому это все еще немного запутанно!
Я обновил свой ответ, надеюсь, теперь понятно.
В вашем примере все совпадения являются статическими строками, поэтому вы можете просто использовать их в качестве ключей словаря для объекта Counter.
import re
from collections import Counter
count = Counter()
for line in lines:
for match in re.finditer(Pattern, line):
count.update(match.group(0))
for k in count.keys():
print(f"{c[k]} occurrences of {k}")
Часть полезных изменений здесь заключается в использовании re.finditer()
вместо re.findall
, который возвращает правильный объект re.Match
, из которого вы можете извлечь совпадающую строку с .group(0)
, а также различные другие атрибуты, если хотите.
Если вам нужно извлечь совпадения, которые могут содержать вариации, такие как r"c[ei]*ling"
или r"\d+"
, вы не можете использовать совпадающие строки в качестве ключей словаря (поскольку тогда Counter
будет считать каждую уникальную строку отдельной сущностью, так что вы получите «12 вхождений 123» и «1 вхождение 234» вместо «13 вхождений \d+
»); в этом случае я, возможно, попытался бы использовать именованные подгруппы.
for match in re.finditer(r"(?P<ceiling>c[ei]*ling)|(?P<number>\d+)", line):
matches = match.groupdict()
for key in matches.keys():
if matches[key] is not None:
count.update(key)
Когда я попытался реализовать это, я заставил его в основном работать, однако он показывает «x вхождений None». Я не уверен, откуда это, у вас есть идеи? Не могли бы вы также объяснить, что делает «f» в последней команде печати? Я вижу, что это необходимо, но я не встречал этого раньше на своих занятиях!
f-строки — это удобный способ встраивания переменных в строки. См., например. docs.python.org/3/tutorial/…
Не видя вашего lines
, трудно ответить конкретно, но я думаю, что у вас есть регулярное выражение, которое ничего не соответствует.
(На самом деле это не приведет к None
; но опять же, без дополнительных деталей отладки мы действительно не можем знать. Если вам нужна дополнительная помощь, возможно, опубликуйте новый вопрос с надлежащим минимально воспроизводимым примером.)
Я получил первый пример, работающий в моем кодировании, спасибо! Я полагаю, что это что-то вроде комбинации этих двух, на самом деле! Я изменил count.update(match.group(0))
на count.update(match.groups())
, который работает для обновления счетчика для каждого совпадения, а затем просто добавил if k is not None:
для цикла for для распечатки результатов!
Просто другой вариант использует numpy
и его метод count_nonzero
. Поскольку нет необходимости разделять данные на строки, предположим, что все в data
:
import numpy as np
# count non-empty strings along axis 0 (the matches for each word)
count = np.count_nonzero(np.array(re.findall(Pattern, data)), 0)
Не используйте один шаблон, используйте столько, сколько вам нужно для подсчета.