Как искать одну или несколько строк в файле с помощью регулярного выражения и подсчитывать количество каждой строки отдельно?

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

Итак, я пробовал следующее (уже прочитав файл и разделив его на строки с помощью .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 будут иметь разные индексы в массиве каждый Переберите.

Не используйте один шаблон, используйте столько, сколько вам нужно для подсчета.

Wiktor Stribiżew 19.04.2023 13:14
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
61
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать 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']) , пожалуйста? Я почти понял, но я все еще новичок в программировании, поэтому это все еще немного запутанно!

Clairlyagenius 19.04.2023 13:34

Я обновил свой ответ, надеюсь, теперь понятно.

coder00 19.04.2023 14:04
Ответ принят как подходящий

В вашем примере все совпадения являются статическими строками, поэтому вы можете просто использовать их в качестве ключей словаря для объекта 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» в последней команде печати? Я вижу, что это необходимо, но я не встречал этого раньше на своих занятиях!

Clairlyagenius 19.04.2023 14:13

f-строки — это удобный способ встраивания переменных в строки. См., например. docs.python.org/3/tutorial/…

tripleee 19.04.2023 14:15

Не видя вашего lines, трудно ответить конкретно, но я думаю, что у вас есть регулярное выражение, которое ничего не соответствует.

tripleee 19.04.2023 14:16

(На самом деле это не приведет к None; но опять же, без дополнительных деталей отладки мы действительно не можем знать. Если вам нужна дополнительная помощь, возможно, опубликуйте новый вопрос с надлежащим минимально воспроизводимым примером.)

tripleee 19.04.2023 14:32

Я получил первый пример, работающий в моем кодировании, спасибо! Я полагаю, что это что-то вроде комбинации этих двух, на самом деле! Я изменил count.update(match.group(0)) на count.update(match.groups()), который работает для обновления счетчика для каждого совпадения, а затем просто добавил if k is not None: для цикла for для распечатки результатов!

Clairlyagenius 19.04.2023 17:19

Просто другой вариант использует 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)

Другие вопросы по теме