Reputation: 29869
Consider the following string:
$foo = @"
cfa7b63c88ed1eb7443daeb12128084f17e1ac80
85e59563f059ecf45c104bef1eac9d70c22150ed
e207411bdb392a2d99719c221c8dd59e0dbebe26
df61cb22643321198656bfa7061c4e415eefdfef
3611ed35610793e814c8aa25715aa582ec08a8b6
089dfe7ceb9a0845342a9637527de65245ba297f qwerty
17570cc9387755367db0fc1c5c5f4757db7fd9b3 asdfgh
82a1be2b77e949cb45581c4d25bf962f77041846 uiop
0b726925f60c17795d4655f8ee37d51a3de70b87 lkjjh
7ed66867332bf06486117189701278cdabd31da6 zxcv
"@
I want to split it into an array of arrays such that the output looks like this:
[0] => [ "089dfe7ceb9a0845342a9637527de65245ba297f", "qwerty" ]
...
[4] => [ "7ed66867332bf06486117189701278cdabd31da6", "zxcv" ]
In other words, an array of 5 elements, with each element being a 2-element array. Note that lines missing the second part (i.e. nothing after the hash) must be excluded.
So far I've got this:
$bar = $foo -split "`r?`n" |?{ $_.length -gt 40 } |%{ $_.split(" ") }
But that results in a single-dimensional array of 10 elements.
Playing around a bit more yields:
$bar = $foo -split "`r?`n" |?{ $_.length -gt 40 } |select { $_.split(" ") }
which gives me an array of 5, but the items in that array are PSCustomObject
s with a NoteProperty
called $_.split(" ")
that is itself an array of 2 strings. So close, yet so far - if I could just flatten out the NoteProperty
I'd be in business!
Is it possible to achieve what I desire, bearing in mind these constraints:
If this is impossible, or there is something I'm fundamentally misunderstanding about how Powershell and its pipelines work (which I very strongly suspect to be the case), please educate me!
Upvotes: 4
Views: 619
Reputation: 23663
If you want to put an array in the pipeline and prevent PowerShell to drop them as separate pipeline items, you will need to force it to a .Net array list by putting a comma in front of the array object:
PS C:\> $bar = $foo -split "`r?`n" | %{ ,$_.split(" ", 2) }
PS C:\> $bar[7]
82a1be2b77e949cb45581c4d25bf962f77041846
uiop
PS C:\> $bar[7][1]
uiop
Upvotes: 5
Reputation: 8432
This is a bit clunky, but I think it meets your requirements:
$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}
The output is an array of arrays (each with a matching line from $foo
), and you can tag a pipeline onto the last bracket and continue processing.
Upvotes: 1