关于数组:Powershell regex split string

Powershell regex split string

我还是 Powershell 的新手;并且无法将我的头转换为一种将字符串转换为对 powershell 友好的对象的方法(转换为 Powershell 属性名称和每个属性名称的相应值,或者,如果这太复杂,则转换为二维数组网格)。理想情况下,我不介意查看每种方式是如何实现的,因此我将来可以采用任何一种方式。无论如何,这是下面的字符串:

1
2
3
4
5
6
7
8
$String =
"   Port      Name               Status       Vlan       Duplex  Speed Type
    Fa1/0/1   Router 2           connected    trunk        full    100 10/100BaseTX
    Fa1/0/2   User               connected    101          full    100 10/100BaseTX
    Fa1/0/3   User               notconnect   101          full    100 10/100BaseTX
    Fa1/0/4   Video VLAN         connected    503          full    100 10/100BaseTX
    Fa1/0/5   User               notconnect   101          full    100 10/100BaseTX
"

由于我的 Powershell 脚本编写经验非常有限,我几乎不能只做一维数组(使用 [regex]::split)。不幸的是,我使用该方法的方式导致数组中的项目为空;而且,它似乎没有像 string.split 那样的 [StringSplitOptions]"RemoveEmptyEntries" 功能。

1
2
type int.txt | %{$data = [regex]::split($_, '(\\s\\s)+')
Write-Output"$($data[0])`t$($data[1])`t$($data[2])`t$($data[3])`t$($data[4])`t$($data[5])`t$($data[6])`t$($data[7])"}

因此,我最终将一些不需要的空项分配给数组;输出如下:

1
2
3
4
5
6
                Port            Name             Status
                Fa1/0/1          Router 2                connected
                Fa1/0/2          User            connected
                Fa1/0/3          User            notconnect
                Fa1/0/4          Video VLAN              connected
                Fa1/0/5          User            notconnect

无论如何,我真的很想要一个专家的解决方案来演示如何将字符串转换为 Powershell 属性和/或二维数组。提前致谢!


如果您正在处理固定宽度的数据,并且不一定相信您会有可预测的分隔符来拆分,那么您可能希望纯粹基于列位置来解析它。您会看到经常使用 string.substring() 方法完成此操作,但您可以使用正则表达式。就个人而言,我更喜欢正则表达式。这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$string =
@'
    Port      Name               Status       Vlan       Duplex  Speed Type
    Fa1/0/1   Router 2           connected    trunk        full    100 10/100BaseTX
    Fa1/0/2   User               connected    101          full    100 10/100BaseTX
    Fa1/0/3   User               notconnect   101          full    100 10/100BaseTX
    Fa1/0/4   Video VLAN         connected    503          full    100 10/100BaseTX
    Fa1/0/5   User               notconnect   101          full    100 10/100BaseTX
'
@



$regex = '(.{10})(.{19})(.{13})(.{11})(.{8})(.{6})(.+)'

$string.split("`n") -notmatch '\\s*Port\\s+' |
 foreach {
  if ($_.trim() -match $regex)
   { [PSCustomObject]@{
     Port   = $Matches[1].trim()
     Name   = $Matches[2].trim()
     Status = $Matches[3].trim()
     Vlan   = $Matches[4].trim()
     Duplex = $Matches[5].trim()
     Speed  = $Matches[6].trim()
     Type   = $Matches[7].trim()
    }
   }
  } | ft -AutoSize



Port    Name       Status     Vlan  Duplex Speed Type        
----    ----       ------     ----  ------ ----- ----        
Fa1/0/1 Router 2   connected  trunk full   100   10/100BaseTX
Fa1/0/2 User       connected  101   full   100   10/100BaseTX
Fa1/0/3 User       notconnect 101   full   100   10/100BaseTX
Fa1/0/4 Video VLAN connected  503   full   100   10/100BaseTX
Fa1/0/5 User       notconnect 101   full   100   10/100BaseTX


这是另一个版本,FWIW:

1
2
3
4
5
6
7
8
9
10
11
12
$regex = '(.{10})(.{19})(.{13})(.{11})(.{8})(.{6})(.+)'
$props = ',Port,Name,Status,Vlan,Duplex,Speed,Type'.split(',')
$ht = [ordered]@{}

$string.split("`n") -notmatch '\\s*Port\\s+' |
 foreach {
  if ($_.trim() -match $regex) {
   for ($i=1;$i -lt $props.count;$i++)
   { $ht[$props[$i]]=$matches[$i]}
   [PSCustomObject]$ht
  }
}

试试这个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$String = @"
    Port      Name               Status       Vlan       Duplex  Speed Type
    Fa1/0/1   Router 2           connected    trunk        full    100 10/100BaseTX
    Fa1/0/2   User               connected    101          full    100 10/100BaseTX
    Fa1/0/3   User               notconnect   101          full    100 10/100BaseTX
    Fa1/0/4   Video VLAN         connected    503          full    100 10/100BaseTX
    Fa1/0/5   User               notconnect   101          full    100 10/100BaseTX
"
@

$temp = $string -split"`n" |
            Foreach {$_ -replace '(\\S+) (\\S+)\\s*$', '$1  $2' -replace '^\\s+',''}

$temp | Foreach {$_ -replace '(?<=\\S) (?=\\S)',[char]0xA0 -replace ' +',' ' } |
        ConvertFrom-Csv -Delimiter ' ' | Format-Table -auto

这通过准备输入字符串来在最后一列和最后一列之间放置两个空格,然后用不间断空格替换剩余的单个空格。


让我们将其转换为 csv 文件,然后将其导入。这将为您提供一个数组,其中包含表示每个接口及其所有属性的对象。

1
2
3
4
5
6
7
8
9
10
11
PS > $a = Get-Content .\\int.txt | Foreach {$_.Trim() -replace ' {2,}',','}  | ConvertFrom-Csv

PS > $a | ft -AutoSize

Port    Name       Status     Vlan  Duplex Speed Type      
----    ----       ------     ----  ------ ----------      
Fa1/0/1 Router 2   connected  trunk full   100 10/100BaseTX
Fa1/0/2 User       connected  101   full   100 10/100BaseTX
Fa1/0/3 User       notconnect 101   full   100 10/100BaseTX
Fa1/0/4 Video VLAN connected  503   full   100 10/100BaseTX
Fa1/0/5 User       notconnect 101   full   100 10/100BaseTX

这也适用于接口名称中的空格,只要单词之间只有一个空格即可。