Другой вариант (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 '"'
Regex ".*?"
соответствует всем "..."
-замкнутым токенам;.Value
извлекает их, а -replace '"'
удаляет "
символов.
Это может быть неочевидно, но это, пожалуй, самое быстрое решение среди ответов здесь, основываясь на моих тестах - см. Ниже.
В качестве отступления: приведенное выше было бы еще более PowerShell-идиоматическим, если бы у оператора -match
- который ищет только a (одно) совпадение - был вариант с именемскажем, -matchall
, чтобы можно было написать:
# WISHFUL THINKING (as of PowerShell Core 6.2)
$str -matchall '".*?"' -replace '"'
См. предложение этой функции на GitHub.
Необязательное чтение: сравнение производительности
Прагматически говоря, все решения здесь полезны и могут быть достаточно быстрыми, но могут быть ситуации, когда производительность должна быть оптимизирована.
Как правило, использование Select-String
(и конвейер в целом) приходитс потерей производительности - предлагая элегантность и эффективность использования памяти потоковая обработка.
Кроме того, повторный вызов блоков скрипта (например, { $_.Value }
) имеет тенденцию быть медленным - особенно в конвейерес ForEach-Object
или Where-Object
, но также - в меньшей степени - с помощью методов сбора .ForEach()
и .Where()
(PSv4 +).
В области регулярных выражений вы платите штраф за производительность за просмотр переменной длины- выражения за (например, (?<=EQUAL\s*")
) и использование групп захвата (например, (.*?)
).
Вот сравнение производительности с использованием функции Time-Command
, в среднем 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'