【问题标题】:Speed optimization of multiple re.match in large files大文件中多次re.match的速度优化
【发布时间】:2022-01-14 11:34:04
【问题描述】:

编辑:添加文件内容的摘要

对于存储为列表的多个大文件(> 10MB),我需要执行不同的匹配和捕获 并使用与group() 匹配的适当数据。

这样做我面临性能问题。使用 re.compile() 可以节省 3 倍,但这还不够。

这是我目前要做的:

import re

results = [
    'EXTRACT for DC ANALYSIS',
    '  PARAM VREF =  1.0500E+00',
    '  TEMPERATURE =  2.5000E+01 Celsius',
    '  ICARLO = 9999',
    '    *VREF_INPUT =  1.0500E+00 Volts',
    '    *VREFSENSEANA =  2.1184E-01 Volts',
    '    *IREFCOMPANA =  1.7614E-05',
    '    *VOFFSET =  1.9432E-03 Volts',
    '    *IRATIO_COMP_PBIAS_DIFF__COMP_PIREFCOMP =  2.1124E+00',
    '    *IRATIO_COMP_PBIAS_OUT__COMP_PIREFCOMP =  1.0503E+00',
    '',
    'EXTRACT for DC TRANSFER CURVES',
    '  PARAM VREF =  1.0500E+00',
    '  TEMPERATURE =  2.5000E+01 Celsius',
    '  ICARLO = 10000',
    '    *VREF_INPUT =  1.0500E+00 Volts',
    '    *VREFSENSEANA =  2.1249E-01 Volts',
    '    *IREFCOMPANA =  1.6552E-05',
    '    *VOFFSET =  2.8657E-03 Volts',
    '    *IRATIO_COMP_PBIAS_DIFF__COMP_PIREFCOMP =  2.0130E+00',
    '    *IRATIO_COMP_PBIAS_OUT__COMP_PIREFCOMP =  1.0142E+00',
    '    *MC_501(VREF_INPUT) =  0.0',
    '    *MC_502(VREF_INPUT) =  1.0000E+00',
    '    *MC_600(VREF_INPUT) =  1.0500E+00',
    '    *MC_907(VREF_INPUT) = FAILED',
    '    *MC_908(VREF_INPUT) =  0.0',
]

re_analysis = re.compile(r'\s*EXTRACT for (\w+)')
re_param = re.compile(r'\s*PARAM\s+(\w+)\s*=\s*(\S+)')
re_alter = re.compile(r'\s*ALTER index (\d+)\s+(\w+)')
re_extract = re.compile(r'\s*\*(\w+)\s*=\s*(\S+)')
re_extract_mc = re.compile(r'\s*\*MC_(\d+)\((\w+)\)\s*=\s*(\S+)')
re_icarlo = re.compile(r'\s*ICARLO\s*=\s*(\d+)')

for line in results:  # self.result is the file stored as list 
    match_analysis = re_analysis.match(line)
    match_param = re_param.match(line)
    match_alter = re_alter.match(line)
    match_extract = re_extract.match(line)
    match_extract_mc = re_extract_mc.match(line)
    match_icarlo = re_icarlo.match(line)
    # do some stuff with the various match and their group()

对于给定的参考文件,整个过程大约需要 0.5 秒,0.35 秒是 6 次匹配的计算。

我希望强烈减少这 0.35 秒的比赛执行时间。

是否有其他方法可以以不同的方式“构建”这 6 个匹配项以加快速度?

或者任何其他不使用正则表达式的方法可以更快?

【问题讨论】:

  • 看起来至少其中一些模式是互斥的。您可以尝试使用命名组将它们组合成一个模式。
  • self.results 中是否有很多行与您的 6 种模式中的任何一种都不匹配?换句话说,有很多行要丢弃吗?
  • @Oliver 您介意提供几个输入以便我们测试您的源代码吗?谢谢
  • @MegaIng:我正在考虑您的建议。我暂时不熟悉命名组
  • @CasimiretHippolyte:绝大多数行将匹配一种模式,除了空白行和一些标题行

标签: python-3.x regex


【解决方案1】:

我找到了一种方法,可以从以下 6 个 @MegaIng 建议中构建一个正则表达式以使用命名组。

不幸的是,执行时间与我最初的解决方案差别不大,可能是由于正则表达式的复杂性?所以,至少对于这个实现,它没有多大帮助。

不管怎样,我把它放在这里作为参考,因为我发现正则表达式的构建很有趣。

# sorry in advance for the eyes ...
regex = re.compile(r'\s*(?P<keyword>EXTRACT|PARAM|ALTER index|\*MC_\d+|\*|ICARLO)\s*\(*(?P<name>\w+)*\)*\s*=*\s*(?P<value>\S+)')

for line in results: 
    match = regex.match(line)
    if match:
        _reg = match.groupdict()
    else:
        continue
    # do stuff using keyword key to known which keyword is seen    
    if _reg['keyword'] == 'PARAM':
        # some stuff with name & value keys

对于我的示例列表,groupdict() 的结果逐行显示:

{'keyword': 'EXTRACT', 'name': 'for', 'value': 'DC'}
{'keyword': 'PARAM', 'name': 'VREF', 'value': '1.0500E+00'}
{'keyword': 'ICARLO', 'name': None, 'value': '9999'}
{'keyword': '*', 'name': 'VREF_INPUT', 'value': '1.0500E+00'}
{'keyword': '*', 'name': 'VREFSENSEANA', 'value': '2.1184E-01'}
{'keyword': '*', 'name': 'IREFCOMPANA', 'value': '1.7614E-05'}
{'keyword': '*', 'name': 'VOFFSET', 'value': '1.9432E-03'}
{'keyword': '*', 'name': 'IRATIO_COMP_PBIAS_DIFF__COMP_PIREFCOMP', 'value': '2.1124E+00'}
{'keyword': '*', 'name': 'IRATIO_COMP_PBIAS_OUT__COMP_PIREFCOMP', 'value': '1.0503E+00'}
{'keyword': 'EXTRACT', 'name': 'for', 'value': 'DC'}
{'keyword': 'PARAM', 'name': 'VREF', 'value': '1.0500E+00'}
{'keyword': 'ICARLO', 'name': None, 'value': '10000'}
{'keyword': '*', 'name': 'VREF_INPUT', 'value': '1.0500E+00'}
{'keyword': '*', 'name': 'VREFSENSEANA', 'value': '2.1249E-01'}
{'keyword': '*', 'name': 'IREFCOMPANA', 'value': '1.6552E-05'}
{'keyword': '*', 'name': 'VOFFSET', 'value': '2.8657E-03'}
{'keyword': '*', 'name': 'IRATIO_COMP_PBIAS_DIFF__COMP_PIREFCOMP', 'value': '2.0130E+00'}
{'keyword': '*', 'name': 'IRATIO_COMP_PBIAS_OUT__COMP_PIREFCOMP', 'value': '1.0142E+00'}
{'keyword': '*MC_501', 'name': 'VREF_INPUT', 'value': '0.0'}
{'keyword': '*MC_502', 'name': 'VREF_INPUT', 'value': '1.0000E+00'}
{'keyword': '*MC_600', 'name': 'VREF_INPUT', 'value': '1.0500E+00'}
{'keyword': '*MC_907', 'name': 'VREF_INPUT', 'value': 'FAILED'}
{'keyword': '*MC_908', 'name': 'VREF_INPUT', 'value': '0.0'}

【讨论】:

    【解决方案2】:

    我终于找到了一个好的解决方案,在每一行上使用基本拆分,而不是正则表达式。

    每一行都可以读成一个句子,这很容易。可以使用列表中的索引或使用最后一个索引[-1]

    捕获所有需要的行元素
    for line in results:
        if line == '':
            continue
        _elems = line.split()
    
        if _elems[0].startswith('*MC_'):
            # do stuff
    
        # ...
    
        if _elems[0] == 'PARAM':
            # do stuff
    

    总执行时间为 0.23 秒,拆分内容大约为 0.07 秒。净收益为 5 倍。

    【讨论】:

      猜你喜欢
      • 2021-03-24
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 2015-10-28
      • 2017-02-08
      • 2021-09-20
      • 1970-01-01
      相关资源
      最近更新 更多