通过此示例字符串
$logLine = '{header[3]}_Pragmatic Praxis Initialization Log'
我正在尝试提取三段数据
header
作为类型3
作为(可选)标签值_
之后的所有字符串我现在拥有的是
$logLine = '{header[3]}_Pragmatic Praxis Initialization Log'
if ($logLine -match '^\{(?<type>[a-z]+)(?:\[?(?<tab>\d?)\]?)\}_(?<string>.+)$') {
Write-Host "$($matches['type'])"
Write-Host "$($matches['tab'])"
Write-Host "$($matches['string'])"
}
运行良好。但是我对RegEx并不熟练,而这是迄今为止我从头开始拼凑而成的最复杂的RegEx,我想知道是否有人看到这种看不见的陷阱?
还是我需要开一些酒,庆祝达到某种RegEx理解里程碑?
编辑: 因此,我的成功使我变得过于自信。我决定将Tab设为必填项,但添加了一个可选的Target,可以是“ console”或“ file”。所以我做到了
$logLine = '{header[3]}_Pragmatic Praxis Initialization Log'
if ($logLine -match '^\{(?<type>[a-z]+)(?:-(?<target>(console|file)))\[(?<tab>\d*)\]\}_(?<string>.+)$') {
Write-Host "$($matches['type'])"
Write-Host "$($matches['target'])"
Write-Host "$($matches['tab'])"
Write-Host "$($matches['string'])"
}
当目标存在时哪个起作用,但当目标不存在时失败。所以,看起来我要学习一些东西,而不是庆祝。 ;)
编辑#2:
根据@Ansgar Wiechers的说法,我的确确实误解了(?:...)
,特别是将它与(....)?
混淆了。基于此,这是我修改过的模式,似乎正在执行我想要的操作。我可能仍然需要target和tab,因为我认为它使代码更易读,同时简化了RegEx模式,但仍然可以像我最初希望的那样工作。
if ($logLine -match '^\{(?<type>[a-z]+)(-(?<target>(console|file)))?(\[(?<tab>\d+)\])?\}_(?<string>.+)') {
Write-Host "$($matches['type'])"
Write-Host "$($matches['target'])"
Write-Host "$($matches['tab'])"
Write-Host "$($matches['string'])"
}
答案 0 :(得分:2)
在我看来,您似乎误解了(?:...)
的工作。该构造未定义可选匹配项,而是定义了非捕获组。 (子)表达式(?:-(?<target>console|file))
将要求字符串包含-console
或-file
并返回console
或file
(无前导连字符)作为已命名匹配“目标”。要使该组为可选,您需要在该组之后 后添加另一个?
。
^\{(?<type>[a-z]+)(?:-(?<target>console|file))?\[(?<tab>\d*)\]\}_(?<string>.+)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
请注意,结尾的表达式.+
或.*
使得将表达式锚定在字符串($
)的末尾毫无意义,因此只需从末尾删除$
表情。
您也不需要console|file
周围的嵌套(未命名)捕获组。命名的捕获组就足够了。