另一种选择 (PSv3+),将 [regex]::Matches() 与 -replace 运算符结合使用以获得简洁的解决方案:
$str = @'
Host
Class
INCLUDE vmware:/?filter=Displayname Equal "server01" OR Displayname Equal "server02" OR Displayname Equal "server03 test"
'@
[regex]::Matches($str, '".*?"').Value -replace '"'
正则表达式".*?" 匹配所有"..." 封闭的标记; .Value 提取它们,-replace '"' 去除 " 字符。
这可能并不明显,但根据我的测试,这恰好是此处答案中最快的解决方案 - 见底部。
顺便说一句:如果 -match 运算符(仅查找 a(一个)匹配项)具有一个名为 -matchall 的变体,则上述内容将更加符合 PowerShell 习惯。 ,这样人们就可以写:
# WISHFUL THINKING (as of PowerShell Core 6.2)
$str -matchall '".*?"' -replace '"'
请参阅 GitHub 上的 this feature suggestion。
选读:性能对比
务实地说,这里的所有解决方案都是有帮助的,并且可能足够快,但可能存在必须优化性能的情况。
一般来说,使用Select-String(以及一般的管道)会带来性能损失 - 同时提供优雅和内存高效的流处理处理。
此外,重复调用脚本块(例如,{ $_.Value })往往会很慢 - 特别是在具有 ForEach-Object 或 Where-Object 的管道中,而且 - 在较小程度上 - 使用 .ForEach() 和 @ 987654339@收集方式(PSv4+)。
在正则表达式领域,您为可变长度的后视表达式(例如(?<=EQUAL\s*"))和使用捕获组(例如(.*?))付出了性能损失。
这是使用Time-Command function 进行的性能比较,平均运行 1000 次:
Time-Command -Count 1e3 { [regex]::Matches($str, '".*?"').Value -replace '"' },
{ [regex]::matches($String, '(?<=Equal\s*")[^"]+') | Foreach {$_.Value} },
{ [regex]::Matches($str, '\"(.*?)\"').Groups.Where({$_.name -eq '1'}).Value },
{ $str | Select-String -Pattern '(?<=Equal\s*")[^"]+' -AllMatches | ForEach-Object{$_.Matches.Value} } |
Format-Table Factor, Command
我的 MacBook Pro 的计时示例;确切的时间并不重要(您可以删除Format-Table 调用以查看它们),但相对性能反映在Factor 列中,从最快到最慢。
Factor Command
------ -------
1.00 [regex]::Matches($str, '".*?"').Value -replace '"' # this answer
2.85 [regex]::Matches($str, '\"(.*?)\"').Groups.Where({$_.name -eq '1'}).Value # AdminOfThings'
6.07 [regex]::matches($String, '(?<=Equal\s*")[^"]+') | Foreach {$_.Value} # Wiktor's
8.35 $str | Select-String -Pattern '(?<=Equal\s*")[^"]+' -AllMatches | ForEach-Object{$_.Matches.Value} # LotPings'