【发布时间】:2021-09-16 12:32:13
【问题描述】:
我正在尝试验证包含一个或多个标记的字符串,其格式为 [Item~SomeNameHere],该标记的颠覆为 [Item~Incerement***],其中 *** 是我稍后将进一步验证的多种可能性。关键是增量标记必须是字符串中的最终标记。
所以[Item~Increment] 有效,_[Item~modifiedDate][Item~Increment(#)] 有效但_[Item~Increment(#)][Item~modifiedDate] 无效。目标是一个非常灵活的面包屑功能,然后这些标记将被替换为最终文件或文件夹名称的其他数据。
为此,我从这个正则表达式 \[Item~Increment.*\] 开始,它确实在字符串中找到了标记。因此,我对其进行了修改,以使用\[Item~Increment.*\]$ 查找字符串末尾的标记,这可以正常工作,直到像[Item~Increment(#)][Item~modifiedDate] 这样的示例,其中.* 匹配(#)][Item~modifiedDate 并在需要False 的地方生成True。不知何故,我需要. 任何字符,不包括[ 或],零次或多次。但是\[Item~Increment[.-\[\]]*\]$ 并没有完成工作,我现在已经超出了我的 RegEx 深度。我也试过用\[Item~Increment[^\[\]]*\]$ 否定它,它也失败了,总是错误的。
编辑:澄清一下,增量标记只能出现一次并且只能在最后出现。但是,在字符串的前面可能有其他形式为[Item~???] 或[???~???] 的标记,也可能有文字字符。所以-[Some~String]_[Item~Date]_[Item~Increment] 是有效的。
根据@wiktor-stribiżew 的回答,我对内容进行了一些改进,并转录为 PowerShell 命名法,现在我有了这个......
$breadcrumbs = @('none', '[Item~Increment]', '[Item~Increment(#)]', '[Item~modifiedDate][Item~Increment(#)]', '[Item~Increment][Item~modifiedDate]', '[Item~Increment][Item~Increment]')
$pattern = '(?:\[Item~[^][]*])*\[Item~Increment[^][]*]$'
CLS
foreach ($breadcrumb in $breadcrumbs) {
Write-Host "$([regex]::matches($breadcrumb, $pattern).Count) $breadcrumb"
}
生产...
0 none
1 [Item~Increment]
1 [Item~Increment(#)]
1 [Item~modifiedDate][Item~Increment(#)]
0 [Item~Increment][Item~modifiedDate]
1 [Item~Increment][Item~Increment]
理论上第一个应该失败,因为没有增量令牌理论上第一个应该通过,因为没有不正确的令牌,最后一个应该失败,因为有两个增量令牌,并且倒数第二个应该失败,因为有一个增量标记不在字符串的末尾。
但是这个 RegEx 在最终测试中失败了,我认为是因为 [Item~Increment][Item~Increment] 被匹配为
[Item~Increment][Item~Increment]
其中][Item~Increment 是变量内容。
这是我错误地转录到 PowerShell 吗?或者,RegEx 是否需要更多的东西来确保 [ 和 ] 不会出现在令牌内,因此这个例子会产生两个计数或失败。我不介意需要另一个计数测试,因为这是为用户生成的有用错误。但就目前而言,我得到的计数是 1,这是无效的。
EDIT2:Doj 的回答也很有趣,而且也更短。对于最后一个示例,使用\[Item~Increment[^\[\]]*\] 我得到的计数为 2,但未处理订单。将其修改为像这样\[Item~Increment[^\[\]]*\]$ 并处理订单,但不再是倍数。呃。
EDIT3:根据 Doj 的回答结合这两种模式让我明白了这一点
foreach ($breadcrumb in $breadcrumbs) {
$incrementCount = ([regex]::matches($breadcrumb, '\[Item~Increment[^\[\]]*\]')).Count
if ($incrementCount -eq 0) {
Write-Host "$breadcrumb good"
} elseif ($incrementCount -gt 1) {
Write-Host 'Duplicate [Item~Increment] tokens'
} else {
if (([regex]::matches($breadcrumb, '\[Item~Increment[^\[\]]*\]$')).Count -ne 0) {
Write-Host "$breadcrumb good"
} else {
Write-Host '[Item~Increment] token not at the end of the string'
}
}
}
产生...
none good
[Item~Increment] good
[Item~Increment(#)] good
[Item~modifiedDate][Item~Increment(#)] good
[Item~Increment] token not at the end of the string
Duplicate [Item~Increment] tokens
我要去参加比赛了!
EDIT4:因为学习两种做事的方法总是比一种更好,所以我修改了 Wiktor 的 PS 方法,就像这样......
$breadcrumbs = @('none', '[Item~Increment]', '[Item~Increment%]', '[Item~modifiedDate][Item~Increment%]', '[Item~Increment][Item~modifiedDate]', '[Item~Increment][Item~Increment%]', '[Item~Increment]_')
CLS
foreach ($breadcrumb in $breadcrumbs) {
if ($breadcrumb -match '\A(?:\[Item~(?!Increment[^][]*])[^][]*])*\[Item~Increment[^][]*]\z') {
Write-Host "$breadcrumb good"
} else {
Write-Host "!!! $breadcrumb"
}
}
这会产生不正确的结果。
!!!没有 [项目~增量] 好 [Item~Increment%] 好 [Item~modifiedDate][Item~Increment%] 好 !!! [项目~增量][项目~修改日期] !!! [项目~增量][项目~增量%] !!! [项目~增量]_
我认为那里有两个不正确的结果,但我使用了错误的模式。 :(
【问题讨论】:
-
不是 Powershell 人,但一般
]需要是字符类中的第一个字符,或者是否定字符类中^之后的第二个字符。 -
'_[Item~modifiedDate][Item~Increment(#)]' -match '\[Item~Increment[^\[\]]*\]$'返回True,'_[Item~Increment(#)][Item~modifiedDate]' -match '\[Item~Increment[^\[\]]*\]$'返回False。这就是你想要的,不是吗?
标签: regex powershell regex-negation