使用re比较多个文件项

时间:2014-10-08 00:59:55

标签: python regex file-io

目前我有一个脚本可以查找多个输入文件中包含格式为的内容的所有行 Matches: 500 (54.3 %)并以百分比打印出前10名最高匹配。

我希望能够输出得分前10行:得分:4000

import re

def get_values_from_file(filename):
    f = open(filename)
    winpat = re.compile("([\d\.]+)\%")
    xinpat = re.compile("[\d]") #ISSUE, is this the right regex for it? Score: 500****

    values = []
    scores = []

    for line in f.readlines():
        if line.find("Matches") >=0:
        percn = float(winpat.findall(line)[0])
        values.append(percn)

    elif line.find("Score") >=0:
        hey = float(xinpat.findall(line)[0])
        scores.append(hey)
    return (scores,values)


all_values = []    
all_scores = []

for filename in ["out0.txt", "out1.txt"]:#and so on
values = get_values_from_file(filename)
all_values += values
all_scores += scores

all_values.sort()
all_values.reverse()

all_scores.sort()  #also for scores
all_scores.reverse()

print(all_values[0:10])
print(all_scores[0:10])

我的正则表达式是否正确?我相信我遇到了这个问题,因为它没有正确输出。

有什么想法?我应该把它分成两个函数吗?

谢谢。

2 个答案:

答案 0 :(得分:1)

没有。 xinpat只匹配单个数字,因此findall()将返回单个数字列表,这有点混乱。将其更改为

xinpat = re.compile("[\d]+")

实际上,这里不需要方括号,因此您可以将其简化为

xinpat = re.compile("\d+")

BTW,名称winpatxinpat有点不透明。 pat位正常,但是win& xin?并且hey也不是很好。但我猜xinhey只是你决定扩展程序时所构成的临时名称。


我刚注意到的另一件事,你不需要做

all_values.sort()
all_values.reverse()

您可以(并且应该)在一次点击中执行此操作:

all_values.sort(reverse=True)

答案 1 :(得分:1)

  

分数格式的正则表达式是否正确?

不,应该是r"\d+"

  • 您不需要[]。这些括号建立一个表示括号内所有字符的字符类。由于括号内只有一种字符类型,因此它们什么都不做。
  • 您只匹配一个字符。您需要*+来匹配一系列字符。
  • 你的字符串中有一个未转义的反斜杠。使用r前缀允许正则表达式引擎看到反斜杠。

评论:

如果是我,我会让正则表达式完成所有工作,并完全跳过line.find()

#UNTESTED
def get_values_from_file(filename):
    winpat = re.compile(r"Matches:\s*\d+\s*\(([\d\.]+)\%\)")
    xinpat = re.compile(r"Score:\s*([\d]+)")

    values = []
    scores = []

    # Note: "with open() as f" automatically closes f
    with open(filename) as f:
        # Note: "for line in f" more memory efficient
        # than "for line in f.readlines()"
        for line in f:
           win = winpat.match(line)
           xin = xinpat.match(line)
           if win: values.append(float(win.group(0)))
           if xin: scores.append(float(xin.group(0)))
    return (scores,values)

只是为了好玩,这是一个例程的版本,每个文件只调用re.findall一次:

# TESTED

# Compile this only once to save time
pat = re.compile(r'''
    (?mx)                                  # multi-line, verbose
    (?:Matches:\s*\d+\s*\(([\d\.]+)\s*%\)) # "Matches: 300 (43.2%)"
    |
    (?:Score:\s*(\d+))                     # "Score: 4000"
''')
def get_values_from_file(filename):
    with open(filename) as f:
        values, scores = zip(*pat.findall(f.read()))
    values = [float(value) for value in values if value]
    scores = [float(score) for score in scores if score]
    return scores, values