我的字符串:
(01) this is value one (02) and this is 2 (03) and this is number 3
所需结果(键/值对):
(01) this is value one
(02) and this is 2
(03) and this is number 3
到目前为止,我的代码:
$s="(01) this is value one (02) and this is 2 (03) and this is number 3"
$pattern = '(\(\d\d\))(.*)'
$m = $s | select-string $pattern -AllMatches | % {$_.matches} | ForEach-Object { $_.Groups[1].Value }
如何做到这一点?
最佳答案
由于您正在寻找键值对,因此将它们收集在(n个有序的)哈希表中是有意义的。
可以通过基于正则表达式的 -split
运算符来执行拆分,该操作还允许通过捕获组((...)
)在输出数组中包括分隔符regex匹配的部分。
# Input string
$s = '(01) this is value one (02) and this is 2 (03) and this is number 3'
# Initialize the output hashtable
$ht = [ordered] @{}
# Split the input string and fill the hashtable.
$i = 0;
$s -split '(\(\d+\)) ' -ne '' | ForEach-Object {
if (++$i % 2) { $key = $_ } else { $ht[$key] = $_ }
}
# Output the hashtable
$ht
以上 yield :
Name Value
---- -----
(01) this is value one
(02) and this is 2
(03) and this is number 3
注意:如果您不想在关键字(名称)属性中包含封闭的
(...)
,请使用-split '\((\d+)\) '
而不是-split '(\(\d+\)) '
上面将字符串拆分为数组的元素,其中相邻元素对代表键值对。然后,
ForEach-Object
调用将这些键值对添加到输出哈希表,根据元素索引是奇数还是偶数来确定输入元素是键还是值。至于您尝试了什么:
您的正则表达式
'(\(\d\d\))(.*)'
过于贪婪,这意味着由于.*
子表达式,给定行上的单个匹配项将匹配整行。如果使用以下正则表达式,则将获得所需的匹配项:
'(\(\d+\)) ([^(]+)'
也就是说,在匹配诸如
(01)
之类的索引之后,仅匹配直到但不包括后续(
(如果有)。在原始命令的简化版本的上下文中,该将键值对输出为自定义对象(
[pscustomobject]
实例)的数组:$s = '(01) this is value one (02) and this is 2 (03) and this is number 3'
$pattern = '(\(\d+\)) ([^(]+)'
$s | Select-String $pattern -AllMatches | ForEach-Object {
$_.matches | Select-Object @{ n='Name'; e = { $_.Groups[1].Value } },
@{ n='Value'; e = { $_.Groups[2].Value } }
}
以上 yield :
Name Value
---- -----
(01) this is value one
(02) and this is 2
(03) and this is number 3
但是请注意,上面的代码输出了一个自定义对象数组,每个对象代表一个键值对,这与顶部的解决方案不同,后者创建了一个包含所有键值对的哈希表。
关于regex - 使用正则表达式提取(重复)包含括号的组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53618458/