如何使用正则表达式在文件中搜索一个或多个字符串,并分别计算每个字符串的数量?

How to search for one or more strings in a file using regex, and count the number of each string separately?

提问人:Clairlyagenius 提问时间:4/19/2023 更新时间:4/19/2023 访问量:80

问:

因此,我试图在文件的每一行中找到一个或多个字符串,并计算每个字符串在文件中出现的次数。在某些行中只有一个字符串,但在其他行中,如果这有意义,可能会有多个目标字符串。我正在尝试使用正则表达式来执行此操作。

所以我尝试的如下(已经读取了文件并使用 .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 中的匹配项在数组中具有不同的索引每次循环。

Python 正则表达式 搜索 字符串匹配

评论

0赞 Wiktor Stribiżew 4/19/2023
不要使用单一模式,使用需要计数的尽可能多的模式。

答:

1赞 TanjiroLL 4/19/2023 #1

您可以在最后使用和计算出现次数。 例如: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', ''), ...]

例如,在计算时,我们正在创建一个与 String1 匹配的元素列表(这里我们看到的条件,元组的第一个元素等于 'String1'),如下所示:count1

first_group = [el for el in all_matches if el[0] == 'String1']

然后我们将其长度返回为这些元素的 count1length 值:

count1 = len(first_group)

评论

0赞 Clairlyagenius 4/19/2023
你能用 count=len([el for el in all_matches if el[0] == 'String1']) 再解释一下最后发生了什么吗?我几乎可以理解它,但我还是编程新手,所以它仍然有点混乱!
0赞 TanjiroLL 4/19/2023
我更新了我的答案,希望现在很清楚。
1赞 tripleee 4/19/2023 #2

在示例中,匹配项都是静态字符串,因此您可以将它们用作 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}")

这里的部分有用的更改是使用 instead of which 返回一个适当的对象,如果您愿意,您可以从中提取匹配的字符串以及各种其他属性。re.finditer()re.findallre.Match.group(0)

如果你需要提取可能包含变体的匹配项,比如 或 ,你不能将匹配的字符串用作字典键(因为这样会将每个唯一的字符串视为一个单独的实体;所以你会得到“12 次出现 123”和“1 次出现 234”而不是“13 次出现”);在这种情况下,我可能会尝试使用命名子组。r"c[ei]*ling"r"\d+"Counter\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)

评论

0赞 Clairlyagenius 4/19/2023
当我尝试实现它时,我让它大部分工作,但它显示“无的 x 次”。我不确定这是从哪里来的,你知道吗?您能否解释一下“f”在最后一个打印命令中的作用?我可以看到这是必要的,但我以前在课堂上没有遇到过!
0赞 tripleee 4/19/2023
F 字符串是在字符串中嵌入变量的便捷方法。例如,参见 docs.python.org/3/tutorial/...
0赞 tripleee 4/19/2023
没有看到你的,很难具体回答,但我想你有一个不匹配的正则表达式。lines
0赞 tripleee 4/19/2023
(实际上,这不会产生;但同样,如果没有更多的调试细节,我们真的无法知道。如果您需要更多帮助,也许可以发布一个新问题,其中包含适当的最小可重复示例None
1赞 Clairlyagenius 4/19/2023
我已经得到了第一个在我的编码中工作的例子,谢谢!我想这实际上是两者的结合!我更改为 ,它适用于更新每个匹配项的计数,然后刚刚添加了用于打印结果的 for 循环!count.update(match.group(0))count.update(match.groups())if k is not None:
1赞 Armali 4/19/2023 #3

只是另一个变体正在使用及其方法。由于没有必要将数据分成几行,让我们假设它全部在:numpycount_nonzerodata

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)