首页 > 解决方案 > 如何以非贪婪的方式使用正则表达式提取跨越多行的字符串?

问题描述

我正在探索使用 json 数据结构标记 MarkDown 文件的可能性。

json 数据可以通过将它们放在“评论”中来隐藏打印输出,请参阅StackOverflow - Markdown 中的评论

[json]:# (
[
    "json goes here"
]
)

为了提取我一直在使用正则表达式的 json 标签并想出

\[json]:#.\(([^*]*)\)

但是,这仅适用于我在 md 文件中只有一个 [json]-tag 的情况。
(见一个标签

使用多个标签时,正则表达式会变得贪婪并包含第一个标签和最后一个标签之间的所有内容:/
(请参阅多个标签

这是重现问题的示例代码

$md = @'
[json]:# (
[
    {"jira": "proj-4753"},
    {"creation": "2021-09-25"}
]
)

# Title

## 1. Conclusion
Jada, jada

## 2. Recomendation
blah, blah

[json]:# (
[
    {"sensitivity": "internal"}
]
)

More data

[json]:# (
[
    {"uid": "abc002334"}
]
)
[json]:# (
[
    {"mode": "hallow"}
]
)
and this
'@

($md | Select-String '\[json]:#.\(([^*]*)\)').Matches.Value

没有提供输出,因为它将是除了最后一行之外的完整 md

...

使用多个标签并指定标签 2 时的正确输出示例应该是

($md | Select-String '<a working regexp>' -AllMatches).Matches[1].Value

[json]:# (
[
    {"sensitivity": "internal"}
]
)
($md | Select-String '<a working regexp>' -AllMatches).Matches.Value

[json]:# (
[
    {"jira": "proj-4753"},
    {"creation": "2021-09-25"}
]
)
[json]:# (
[
    {"sensitivity": "internal"}
]
)
[json]:# (
[
    {"uid": "abc002334"}
]
)
[json]:# (
[
    {"mode": "hallow"}
]
)

我当然可以选择每个 md 只使用一个 [json] 标签。
还有一个可选的解决方案是将标签只保留在一行上,但这会妨碍可读性。
这不会产生非常健壮的代码,因为有两个非常可能的场景(多标签和多行标签)会破坏代码。

标签: regexpowershellmarkdown

解决方案


由于有效的 json 注释后面总是跟一个换行符\n,然后是一个右括号),所以使用它作为你的模式结束锚:

if($md -match '(?s)\[json]:#.\(\s*(.*?)\s*\n\)'){
  $Matches[1]
}

(?s)“单行模式”的正则表达式引擎选项,它.匹配换行符,允许我们使用.*?.

$Matches一个自动变量-match,当操作在标量模式下成功时,将填充所有捕获组值。

结果:

[
    {"jira": "proj-4753"},
    {"creation": "2021-09-25"}
]

推荐阅读