regex查找重复标记之间的字符串

vs3odd8k  于 12个月前  发布在  其他
关注(0)|答案(4)|浏览(108)

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

**** 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.....

字符串
我想要一个捕获组,它可以捕获从“[1]”到以[5]开头的行的末尾的所有内容,基于远程主机名(例如PNR或PNQ)。因此,只能捕获选定名称周围的行[1]到[5]。
我一直在尝试lookahead和lookbehind,就是想不通。看起来lookbehind是贪婪的,所以如果我搜索PNR部分,它不会停在第一个[1],而是抓取PNQ部分中第一个[1]之前的所有内容。
这是我最接近使它工作的方法,但只有当我搜索PNQ部分时才有效:

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


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

wsewodh2

wsewodh21#

您可以使用没有re.DOTALL标志但带有re.MULTILINE标志的模式:

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

字符串
模式匹配:

  • \bSOURCE#从单词边界开始匹配
  • .*匹配行的其余部分
  • \s*^匹配可选的空格字符,直到行的开头
  • \[1]匹配[1]
  • (捕获组1
  • .*匹配行的其余部分
  • \s*^匹配可选的空格字符,直到行的开头
  • (?!\[\d+])负先行,Assert行不以[digits]开始
  • .*\bPN[QR]在行尾匹配PNBPNQ
  • (?:\n(?!\[\d+]).*)*匹配以下所有不以[digits]开头的行
  • (?:\n\[\d+].*)*匹配以下以[digits]开头的所有行
  • )关闭组1

查看仅使用PNR和Python demo不会过度匹配的regex demoa demo

kadbb459

kadbb4592#

如果你需要为numbered-filtered items创建一个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"
    }
}

0qx6xfy6

0qx6xfy63#

  • "..

试试下面的匹配模式。

(?ms)^\[1\].+?Remote Host Name\s*:\s*(?:PNR|PNQ).+?^\[5\].+?$

字符串

  • (?ms),切换 “多行”“单行”,模式
  • ^\[1\],匹配以文本开头的行,"[1]"
  • .+?Remote Host Name\s*:\s*(?:PNR|PNQ),匹配所有字符,直到文本 “远程主机名”、可选空格字符、":“、后跟 “PNR”“PNQ”
  • .+?^\[5\],匹配所有字符,直到以 "[5]" 开头的第一行
  • .+?$,匹配到第一个字符的所有字符,行尾

这里有一个例子,其中 s 是文本。

import re
p = r'(?ms)^\[1\].+?Remote Host Name\s*:\s*(?:PNR|PNQ).+?^\[5\].+?$'
[print(m.group(), end='\n\n') for m in re.finditer(p, s)]


输出

[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
[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

的字符串

unhi4e5o

unhi4e5o4#

感谢大家的帮助。虽然没有一个建议是“开箱即用”的(我尝试了所有的),但我利用每个块都以“:\d+”结尾的事实,设法拼凑出了一些有用的东西。此外,我忘了提到块可以是任何大小,从[1]到[x]。我最终使用的正则表达式是:

re.search(r'\*\s*SOURCE.*?\[1\].*(?:PNR)(.*?HDPGWRF.*?:\ \d+)\n\n', buf, re.DOTALL).group(1)

字符串
(?:PNR)是缺失的部分,让我忙碌,不能弄清楚。

相关问题