使用管道将字符串分割成多维数组

4
请看下面的字符串:

考虑以下字符串:

$foo = @"
cfa7b63c88ed1eb7443daeb12128084f17e1ac80
85e59563f059ecf45c104bef1eac9d70c22150ed
e207411bdb392a2d99719c221c8dd59e0dbebe26
df61cb22643321198656bfa7061c4e415eefdfef
3611ed35610793e814c8aa25715aa582ec08a8b6
089dfe7ceb9a0845342a9637527de65245ba297f qwerty
17570cc9387755367db0fc1c5c5f4757db7fd9b3 asdfgh
82a1be2b77e949cb45581c4d25bf962f77041846 uiop
0b726925f60c17795d4655f8ee37d51a3de70b87 lkjjh
7ed66867332bf06486117189701278cdabd31da6 zxcv
"@

我希望将其拆分为一个数组的数组,使输出看起来像这样:
[0] => [ "089dfe7ceb9a0845342a9637527de65245ba297f", "qwerty" ]
...
[4] => [ "7ed66867332bf06486117189701278cdabd31da6", "zxcv" ]

换句话说,这是一个由5个元素组成的数组,每个元素都是一个包含2个元素的数组。请注意,缺少第二部分(即#后面没有内容)的行必须被排除掉。
到目前为止,我已经得到了这个:
$bar = $foo -split "`r?`n" |?{ $_.length -gt 40 } |%{ $_.split(" ") }

但这会导致一个只有10个元素的一维数组。

再做些微调可以得到:

$bar = $foo -split "`r?`n" |?{ $_.length -gt 40 } |select { $_.split(" ") }

这给了我一个长度为5的数组,但是该数组中的项目是PSCustomObject,带有名为$_.split(" ")NoteProperty,它本身是包含2个字符串的数组。离成功很接近,如果我只能拆开NoteProperty,就可以做成了!

请注意以下限制条件,是否可以实现我所需的操作:

  • 所有操作必须通过管道完成
  • 不得显式命名哈希表元素等 - 我想使用

如果这是不可能的,或者我对Powershell及其管道工作方式存在基本的误解(我非常强烈地怀疑这种情况),请指导我!

2个回答

5

如果你想要将一个数组放入管道,并且不想让PowerShell把它们作为独立的管道项来处理,你需要通过在数组对象前面加上逗号,将其强制转换为.Net数组列表:

PS C:\> $bar = $foo -split "`r?`n" | %{ ,$_.split(" ", 2) }
PS C:\> $bar[7]
82a1be2b77e949cb45581c4d25bf962f77041846
uiop
PS C:\> $bar[7][1]
uiop

这不会丢弃空的第二个元素 $bar =$foo -split '\r?\n'| ? {$_ -match '([0-9a-f]{40}) ([^ ].*)'}|%{ ,$_.split(" ") } - user6811411
如果文件名中有空格,它还将创建一个锯齿数组。 - user6811411
1
@LotPings,对于第一个评论;如果第二个元素不存在(除非有尾随空格),它们确实不会被删除,但这不应该是问题,因为例如$bar[1][1]返回$Null(没有错误),在大多数情况下自动将其与其他字符串类型转换。如果没有,您可以通过"$($Bar[1][1])"强制将其转换为字符串。对于第二个评论,您可以使用.Net Split方法的第二个重载参数来限制字符串数量为2(更新的答案),这将使第二个元素中保留空格:在您的示例中,$bar[8][1]现在返回lkjjh test mess - iRon
1
做得好!要删除单字段行,您可以在“-split”\r?\n之后插入-match ' ' - mklement0
我喜欢PS,但这些小问题真是让人沮丧!你们都太棒了,特别是@iRon。 - Ian Kemp

1
这段代码有点笨重,但我认为它符合你的要求:
$foo = @"
cfa7b63c88ed1eb7443daeb12128084f17e1ac80
85e59563f059ecf45c104bef1eac9d70c22150ed
e207411bdb392a2d99719c221c8dd59e0dbebe26
df61cb22643321198656bfa7061c4e415eefdfef
3611ed35610793e814c8aa25715aa582ec08a8b6
089dfe7ceb9a0845342a9637527de65245ba297f qwerty
17570cc9387755367db0fc1c5c5f4757db7fd9b3 asdfgh
82a1be2b77e949cb45581c4d25bf962f77041846 uiop
0b726925f60c17795d4655f8ee37d51a3de70b87 lkjjh
7ed66867332bf06486117189701278cdabd31da6 zxcv
"@

$foo | ForEach-Object {$array = New-Object System.Collections.ArrayList}{
    $match = [Regex]::Match($foo, "(?<code1>\w+) (?<code2>\w+)")

    while($match.Success)
    {
        $array.Add(@($match.Groups["code1"].Value, $match.Groups["code2"].Value)) | Out-Null

        $match = $match.NextMatch()
    }
}{$array}

输出是一个数组的数组(每个数组与$foo中的一行相匹配),您可以在最后一个括号上标记一个管道并继续处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接