任何改进 Python 字符串解析的建议

Any suggestions to improve Python string parsing

我是 运行 Python 3.6.8。我需要对日志文件中出现的值求和。该行可能包含 1 到 14 个 {index,value} 对; 8 个值的典型行在下面的代码中(变量称为 'log_line')。以'- -'分隔符的行格式是一致的。我有工作代码,但我不确定这是否是解析此字符串的最优雅或最佳方式;感觉有点笨重。有什么建议吗?

    import re
    
    #verion 1
    log_line = 'Some explanatory text was here:      - -{0, 8} {1, 24} {2, 24} {3, 5} {4, 5} {5, 12} {6, 12} {7, 5}'
    log_line_values = log_line.split('- -')[1]
    values = re.findall(r'{\d+,\s\d+}',log_line_values)
    sum_of_values = 0
    for v in values:
        sum_of_values += int(v.replace('{','').replace('}','').replace(' ','').split(',')[1])
    print(f'1) sum_of_values:{sum_of_values}')

    #verions 2, essentially the same, but more concise (some may say confusing)
    sum_of_values = sum([int(v.replace('{','').replace('}','').replace(' ','').split(',')[1]) for v in re.findall(r'{\d+,\s\d+}',log_line.split('- -')[1])])
    print(f'2) sum_of_values:{sum_of_values}')

首先,无需删除前缀 - 正则表达式会处理不匹配的问题。其次,我们可以使用捕获组来捕获我们只关心的值。在我们的例子中,逗号分隔对中的第二个值。我们可以使用 map(int, iterable) 将每个字符串转换为列表中的一个 int,然后我们可以对该数字列表使用 sum。

综合起来:

import re

log_line = 'Some explanatory text was here:      - -{0, 8} {1, 24} {2, 24} {3, 5} {4, 5} {5, 12} {6, 12} {7, 5}'
values = re.findall(r'{\d+,\s(\d+)}', log_line_values)
sum_of_values = sum(map(int, values))

正则表达式捕获组的理想用例:

import re

log_line = 'Some explanatory text was here:      - -{0, 8} {1, 24} {2, 24} {3, 5} {4, 5} {5, 12} {6, 12} {7, 5}'
pattern = r'{(\d+), (\d+)}'

s = sum([int(e[1]) for e in re.findall(pattern, log_line.split('- -')[1])])

print(s) # 95

这里我使用 re.findall 匹配输入数组中的数字,并使用列表理解将它们转换为数字并求和。

使用 {(\d+), (\d+)} 模式的优点是能够提取第一个数字(如果需要)。

假设您已经确定该行与模式匹配,您可以通过在 sum() 中使用生成器表达式来大大简化您的逻辑。

import re

# Compile your regular expression for reuse
# Just pull out the last value from each pair
re_extract_val = re.compile(r'{\d+, (\d+)}')

log_line = 'Some explanatory text was here:      - -{0, 8} {1, 24} {2, 24} {3, 5} {4, 5} {5, 12} {6, 12} {7, 5}'

# Use generator comprehension within sum() to add all values
sum_of_values = sum(int(val) for val in re_extract_val.findall(log_line))

您也可以使用 map(),但我发现使用生成器表达式更清晰

sum_of_values = sum(map(int, re_extract_val.findall(log_line)))