正则表达式查找重复标记之间的字符串

问题描述 投票:0回答:2

我有一个看起来像这样的字符串:

**** SOURCE#24 ****

[1]  Source Location [Local/Remote]          : Remote

 Remote Host Name : PNQ
 User Name        : foo

[2]  Source directory                        : HDPGWRF
[3]  Directory poll interval                 : 30
[4]  File name format                        : ACR_FILEFORMAT
[5]  Delete files from source                : y

**** SOURCE#25 ****

[1]  Source Location [Local/Remote]          : Remote

 Remote Host Name : PNR
 User Name        : foo

[2]  Source directory                        : HDPGWRF
[3]  Directory poll interval                 : 30
[4]  File name format                        : ACR_FILEFORMAT
[5]  Delete files from source                : y

**** SOURCE#26 ****
etc.....

我想要一个捕获组,根据远程主机名(例如 PNR 或 PNQ)捕获“[1]”之后直到以 [5] 开头的行末尾的所有内容。因此,所选名称周围只有 [1] 到 [5] 行。

我一直在尝试向前看和向后看,但就是无法弄清楚这一点。看起来后视是贪婪的,所以如果我搜索 PNR 部分,它不会停在第一个 [1] 处,而是抓取 PNQ 部分中第一个 [1] 之前的所有内容。

这是我最接近使其工作的方法,但只有当我搜索 PNQ 部分时它才有效:

re.search('SOURCE#.*?\[1\](.*?PNQ.*?.*?HDPGWRF.*?)\*', buf, flags=re.DOTALL).group(1)

这是在梳理了整个 stackoverflow 之后的:(

python regex pattern-matching multiple-occurrence
2个回答
0
投票

您可以使用不带

re.DOTALL
标志但带有
re.MULTILINE
标志的模式:

\bSOURCE#.*\s*^\[1](.*\s*^(?!\[\d+]).*\bPN[QR](?:\n(?!\[\d+]).*)*(?:\n\[\d+].*)*)

模式匹配:

  • \bSOURCE#
    从单词边界开始字面匹配
  • .*
    匹配该行的其余部分
  • \s*^
    匹配可选的空白字符直到行首
  • \[1]
    匹配
    [1]
  • (
    捕获第 1 组
    • .*
      与该行的其余部分匹配
    • \s*^
      匹配可选的空白字符直到行首
    • (?!\[\d+])
      负向前瞻,断言各行不以
      [digits]
    • 开头
    • .*\bPN[QR]
      匹配行尾的
      PNB
      PNQ
    • (?:\n(?!\[\d+]).*)*
      匹配所有以下不以
      [digits]
    • 开头的行
    • (?:\n\[\d+].*)*
      匹配以下所有以
      [digits]
    • 开头的行
  • )
    关闭第 1 组

查看 regex 演示a 演示,仅使用 PNR 和 Python 演示

不会过度匹配

0
投票

如果您需要创建编号过滤项的Python对象,您可以尝试:

import re

targets = ["PNR", "PNQ"]

with open("file.txt") as f:
    pat = r"\*+\ (SOURCE#\d+) \*+\s+(.+?Remote Host Name : (\w+).+?)(?=\*)"
    
    data = {
        m.group(1) : dict(re.findall(r"\[\d+\]\s*(.+?)\s*:\s*(.+)", m.group(2)))
        for m in re.finditer(pat, f.read(), flags=re.M|re.S)
        if m.group(3) in targets # or ["PNR", "PNQ"]
    }

输出:

import json; print(json.dumps(data, indent=4))

{
    "SOURCE#24": {
        "Source Location [Local/Remote]": "Remote",
        "Source directory": "HDPGWRF",
        "Directory poll interval": "30",
        "File name format": "ACR_FILEFORMAT",
        "Delete files from source": "y"
    },
    "SOURCE#25": {
        "Source Location [Local/Remote]": "Remote",
        "Source directory": "HDPGWRF",
        "Directory poll interval": "30",
        "File name format": "ACR_FILEFORMAT",
        "Delete files from source": "y"
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.