复杂的命名匹配组RegEx审核

时间:2019-01-28 11:04:39

标签: regex powershell

通过此示例字符串

$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'])"
}

1 个答案:

答案 0 :(得分:2)

在我看来,您似乎误解了(?:...)的工作。该构造未定义可选匹配项,而是定义了非捕获组。 (子)表达式(?:-(?<target>console|file))将要求字符串包含-console-file并返回consolefile(无前导连字符)作为已命名匹配“目标”。要使该组为可选,您需要在该组之后 后添加另一个?

^\{(?<type>[a-z]+)(?:-(?<target>console|file))?\[(?<tab>\d*)\]\}_(?<string>.+)
#                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

请注意,结尾的表达式.+.*使得将表达式锚定在字符串($)的末尾毫无意义,因此只需从末尾删除$表情。

您也不需要console|file周围的嵌套(未命名)捕获组。命名的捕获组就足够了。