使用Powershell的分割方法有问题

时间:2019-09-13 12:02:00

标签: powershell split

我有一个xml文件,其中有一些行

<!--<__AMAZONSITE id="-123456780" instance ="CATZ00124"__/>-->

我需要该行中的id和实例值。

我需要在两个不同的变量中分别包含-123456780CATZ00124

下面是我尝试过的示例代码

$xmlfile = 'D:\Test\sample.xml'
$find_string = '__AMAZONSITE'
$array = @((Get-Content $xmlfile) | select-string $find_string)

Write-Host $array.Length

foreach ($commentedline in $array)
{   
   Write-Host $commentedline.Line.Split('id=')   
}

我得到的结果如下:

<!--<__AMAZONSITE 


"-123456780" 
nstance 
"CATZ00124"__/>

2 个答案:

答案 0 :(得分:1)

首选方法仍然是对XML文件使用XML工具。

只要文件中包含AMAZONSITE和instance的行是唯一的,就可以这样做:

## Q:\Test\2019\09\13\SO_57923292.ps1

$xmlfile = 'D:\Test\sample.xml' # '.\sample.xml' #

## see following RegEx live and with explanation on https://regex101.com/r/w34ieh/1
$RE = '(?<=AMAZONSITE id=")(?<id>[\d-]+)" instance ="(?<instance>[^"]+)"'

if((Get-Content $xmlfile -raw) -match $RE){
    $AmazonSiteID = $Matches.id
    $Instance     = $Matches.instance
}

答案 1 :(得分:0)

LotPings' answer明智地建议将regular expressioncapture groups结合使用,以从每个匹配行中提取感兴趣的子字符串。

您可以将其合并到用于单管道解决方案的Select-String调用中(假设所关注的XML注释都在一行中):

# Define the regex to use with Select-String, which both
# matches the lines of interest and captures the substrings of interest 
# ('id' an 'instance' attributes) via capture groups, (...)
$regex = '<!--<__AMAZONSITE id="(.+?)" instance ="(.+?)"__/>-->'

Select-String -LiteralPath $xmlfile -Pattern $regex | ForEach-Object {
    # Output a custom object with properties reflecting
    # the substrings of interest reported by the capture groups.
    [pscustomobject] @{
        id = $_.Matches.Groups[1].Value
        instance = $_.Matches.Groups[2].Value
    }
}

结果是一个自定义对象的数组,每个对象都有一个.id.instance属性,它们具有感兴趣的值(最好设置单个变量);在控制台中,输出看起来像这样:

id         instance
--         --------
-123456780 CATZ00124
-123456781 CATZ00125
-123456782 CATZ00126


关于您尝试过的事情

注意:我正在讨论您对.Split()的使用,尽管出于您的意图提取子字符串 的目的,.Split()并不是最好的工具只是隔离感兴趣的子字符串的第一步。

如LotPings在注释中所述,在Windows PowerShell中,$commentedline.Line.Split('id=')使String.Split()方法将输入字符串除以任何单个字符字符串'id=' ,因为 Windows PowerShell 选择takes a char[] value的方法重载,即字符数组,这不是您的意图

可以通过强制使用overload that accepts string[](即使您仅传递一个字符串)来纠正此问题,如下所示:一个选项参数:

$commentedline.Line.Split([string[] 'id=', 'None') # OK, splits by whole string

请注意,在PowerShell Core 中,逻辑是相反的 ,因为.NET Core引入了new overload with just [string](带有 Optional options参数),默认情况下由PowerShell Core选择。相反,这意味着如果您要做要在PowerShell Core中按任意字符进行拆分,则必须将拆分的字符串强制转换为[char[]]

一般来说, PowerShell具有-split operator ,它是基于 regex 的,并且比{{1} } -参见this answer

适用于您的情况:

String.Split()
  • $commentedline.Line -split 'id=' id=解释为 regex ,由于字符串不包含regex元字符(具有特殊含义的字符),因此此处没有区别;如果您确实希望使用 literal 子字符串进行安全拆分,请使用-split作为RHS。

  • 请注意,[regex]::Escape('...')默认情况下不区分大小写 ,就像PowerShell通常一样;但是,您可以使用-split变体来区分大小写