正则表达式 (pcre) - 解析 ini-like 文件,在不同的嵌套、不带引号的定界符之间

Regex (pcre) - Parse ini-like file, between different nested, unquoted delimiters

在 Regex101 上查看:click here

给定标题、(可能)部分名称和字段名称,我想读取字段的值,有点类似于从 ini 文件中读取值。


例如,对于以下文件:
给定:标题:heading2,部分:(空),字段:field1
输出field names can be repeated among headings.

另一个例子:
给定:标题:heading2,部分:anothersection,字段:field2
输出Regex is harder when I add an @ in a multi-line string, or if I add backslash-escaped characters like \" and \'.

What happens if I have an empty line in a string?

Also, [this line] isn't actually a section.

另一个例子:
给定:标题:aaaaaaa,部分:(空),字段:bbbbb
输出:(无输出;指定的标题、部分或字段不存在)


但是,我的文件与 ini 文件不同。 虽然 ini 文件也有部分,但我的就像一系列串联的 ini 文件,用 @ .. 分隔它们:

@ heading1
field1: "single-line strings are quoted only sometimes."
field2: "strings that span
multiple lines
are always quoted."
field3: this single-line string is unquoted.

@ heading2
field1: field names can be repeated among headings.
field2: "Regex is harder when I add an
@ in a multi-line string, or if I add
backslash-escaped characters like \" and \'.

What happens if I have an empty line in a string?

Also,
[this line]
isn't actually a section."
field3: this field comes after field2
[sectionname]
field1: the same field name under a different section.
[anothersection]
field1: a second section under the same heading
field4: field number four

@ heading3
field1: value value value value value
field2: "quoted string
quoted string
quoted string"
unique: unique field name

我希望能够指定一个标题,可能是一个部分名称和一个字段名称。 如果该字段存在于指定的 header 名称下,则捕获组中的值。我也想匹配整个标题,不管值是否被捕获。

我已经走到这一步了:

^@ heading2$[\s\S]*?^(?:field2: \"?((?<=\")[^"\]*(?:\.[^"\]*)*(?=\"$)|(?<!\").*(?!\")$)\"?$|)?$[\s\S]*?(?=@ [^\s]*?|\Z)
(with gm modifiers)

这完成了我想要的大部分工作,包括处理 multi-line 字符串和 backslash-escaped 引号。

但是,我正在努力解决以下问题:

我当前的正则表达式只避免过度进入下一个 section/heading,因为我使用了包含在 ^$ 中的惰性交替。但是,我不能只依赖 @ .. 之前的空行。如果我在引用值中有一个空行,我将无法搜索它后面的任何字段。

我感觉我用错了正则表达式。感谢您的帮助!

I get the feeling I'm using regex wrong.

确实如此!有一种更简单的方法:您可以使用正则表达式 标记化 该输入,然后使用一些代码来理解它。

这是给你的模式(x):

^@\s*(?<heading>\w+)\s*?$
|^\[(?<section>\w+)\]\s*?$
|^(?<field>\w+):\s*(?:"(?<quotedstr>(?:\.|[^\"]++)*+)"|(?<barestr>.*?))\s*?$

现在看看this demo:

看看不同的颜色如何很好地匹配您可以拥有的不同令牌类型。如果您将文本悬停在 regex101 上,它甚至会在工具提示中告诉您令牌类型(组名)和值。

每场比赛可以是:

  • 一个标题
  • 一段
  • 或一个字段及其值。

因此,只需迭代保持状态(当前标题和当前部分)的匹配项,您就可以轻松应用您想要的任何逻辑。