包含部分不完整嵌套结构的文本文件的正则表达式

2024-10-02 14:21:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我想用这种嵌套格式分析一个文件:

/begin FUNCTION

    foo
    "1.2.12 foo_long"

    /begin DEF1
    /end DEF1
    FUNCTION_VERSION "1.2.0"

/end FUNCTION

/begin FUNCTION

    bar
    ""

/end FUNCTION

/begin FUNCTION

    urbi
    "10.15.23 urbi_long"

    /begin DEF1
    /end DEF1
    FUNCTION_VERSION "10.15.3"

/end FUNCTION

我想从中提取函数名、长名和版本号。你知道吗

我使用以下正则表达式执行此操作:

sSearch = r'/begin FUNCTION\s+(\w*)\s+"[\d\._\s]*([^"]+)*"(.*?)FUNCTION_VERSION\s+"([^"]+)"\s+/end FUNCTION'
lMatches = re.findall(sSearch, sFileContent, re.S)
dMatches = {args[0]: [args[3], args[1]] for args in lMatches if args}
print(dMatches)

这导致:

{'foo': ['1.2.0', 'foo_long'], 'bar': ['10.15.3', '']}

来自urbi的函数版本被错误地分配给bar。我根本不希望bar返回,因为它不包含函数版本。你知道吗

当发现end FUNCTION没有前导function version时,如何调整regex,使其在bar之前释放/begin FUNCTION发生?你知道吗

我希望输出为:

{'foo': ['1.2.0', 'foo_long'], 'urbi': ['10.15.3', 'urbi_long']}
我也困惑的是为什么我需要在中间添加一个不必要的^ {CD8}}捕获组。它不也应该与一个简单的.*一起工作吗?你知道吗


Tags: 函数refooversionbarargsfunctionlong
3条回答

试试这个正则表达式:

\/begin FUNCTION\s*(\w+)\s*"(?:(?!end FUNCTION)[\s\S])*?(\w+)"[\s\S]*?FUNCTION_VERSION\s*"([^"\s]+)"

Click for Demo

说明:

  • \/begin FUNCTION\s*-匹配/begin FUNCTION,后跟0+空格
  • (\w+)-匹配1+个单词字符,并将其捕获到组1中。这是函数的名称
  • \s*"-匹配0+个空格,后跟"
  • (?:(?!end FUNCTION)[\s\S])*?-匹配任何字符直到以短语end FUNCTION开头的标记
  • (\w+)-匹配1+个单词字符并将其存储在组2中。这就是你的名字
  • "[\s\S]*?FUNCTION_VERSION\s*"-匹配",后跟0+个字符,后跟FUNCTION_VERSION,后跟0+个空格,后跟"
  • ([^"\s]+)-匹配1+个既不是"也不是空白的字符。这是在组3中捕获的,包含您的版本号。你知道吗
  • "-匹配"

您可以使用negative lookahead执行此操作,如下所示:

import re

with open('filename.txt') as fd:
    data = fd.read()

regex = re.compile(
    r'begin\s+FUNCTION\s+([a-zA-Z_]+)\s+'
    r'(?:"[\d.]+\d\s+([a-zA-Z_]+)")?'
    r'(?:(?:(?!/end\s+FUNCTION).)+FUNCTION_VERSION\s+"([\d.]+\d)")?',
    re.MULTILINE | re.DOTALL
)
result = {i[0]: [i[2], i[1]] for i in regex.findall(data)}
print(result)

#outpout
{'urbi': ['10.15.3', 'urbi_long'], 'foo': ['1.2.0', 'foo_long'], 'bar': ['', '']}

#refine result
result = {k: [i for i in v if i] for k, v in result.items()}
print(result)

# output
{'urbi': ['10.15.3', 'urbi_long'], 'foo': ['1.2.0', 'foo_long'], 'bar': []}

这是一种使用Lookbehind & Lookahead的方法。你知道吗

演示:

import re

s = """/begin FUNCTION

    foo
    "1.2.0 foo_long"

    /begin DEF1
    /end DEF1
    FUNCTION_VERSION "1.2.0"

/end FUNCTION

/begin FUNCTION

    bar
    ""

/end FUNCTION

/begin FUNCTION

    urbi
    "10.15.3 urbi_long"

    /begin DEF1
    /end DEF1
    FUNCTION_VERSION "10.15.3"

/end FUNCTION"""

result = {}
for i in re.findall(r"(?<=/begin FUNCTION)(.*?)(?=/end FUNCTION)", s, flags=re.DOTALL):
    val = i.strip().splitlines()
    if val:
        try:
            result[val[0]] = val[1].replace('"', "").split()
        except:
            result[val[0]] = []
print(result)

输出:

{'urbi': ['10.15.3', 'urbi_long'], 'foo': ['1.2.0', 'foo_long'], 'bar': []}

相关问题 更多 >