首页 > 解决方案 > 如何使用 Powershell 从多行中选择字符串

问题描述

我在 test.dat 下面有这个文件

        <category>Games</category>
</game>

        <category>Applications</category>
</game>

        <category>Demos</category>
</game>

        <category>Games</category>
        <description>MLB 2002 (USA)</description>
</game>

        <category>Bonus Discs</category>
</game>

        <category>Multimedia</category>
</game>

        <category>Add-Ons</category>
</game>

        <category>Educational</category>
</game>

        <category>Coverdiscs</category>
</game>

        <category>Video</category>
</game>

        <category>Audio</category>
</game>

        <category>Games</category>
</game>

如何使用上述文件的输入Get-Content并将Select-String以下内容输出到终端。使用上面的输入我需要接收这个输出。

            <category>Games</category>
    </game>
            <category>Games</category>
    </game>

这是我目前正在使用的命令,但它不起作用。 Get-Content '.\test.dat' | Select-String -pattern '(^\s+<category>Games<\/category>\n^\s+<\/game>$)'

标签: regexpowershelltextselect-string

解决方案


首先,您需要将其全部作为一个字符串读取以跨行匹配。

Get-Content '.\test.dat' -Raw

由于您似乎想排除条目,因此您可以使用此模式仅抓取那些前后没有空格的条目

'(?s)\s+<category>Games\S+\r?\n</game>'

选择字符串返回一个 matchinfo 对象,您需要提取该Value属性的Matches属性。你可以通过几种不同的方式做到这一点。

Get-Content '.\test.dat' -Raw |
    Select-String '(?s)\s+<category>Games\S+\r?\n</game>' -AllMatches |
        ForEach-Object Matches | ForEach-Object Value

或者

$output = Get-Content '.\test.dat' -Raw |
    Select-String '(?s)\s+<category>Games\S+\r?\n</game>' -AllMatches

$output.Matches.Value

或者

(Get-Content '.\test.dat' -Raw |
    Select-String '(?s)\s+<category>Games\S+\r?\n</game>' -AllMatches).Matches.Value

输出

        <category>Games</category>
</game>


        <category>Games</category>
</game>

您也可以使用[regex]类型加速器。

$str = Get-Content '.\test.dat' -Raw

[regex]::Matches($str,'(?s)\s+<category>Games\S+\r?\n</game>').value

编辑

根据您的附加信息,我理解的方式是您要删除任何空的游戏类别。我们可以通过使用 here 字符串大大简化这一点。

$pattern = @'
        <category>Games</category>
    </game>

'@

额外的空白行是为了捕获最后的换行符。你也可以这样写

$pattern = @'
        <category>Games</category>
    </game>\r?\n
'@

现在,如果我们对模式进行替换,您将看到我认为您对最终结果的期望。

(Get-Content $inputfile -Raw) -replace $pattern

要完成它,您只需将上述命令放在Set-Content命令中即可。由于Get-Content命令包含在括号中,因此在写入文件之前将其完全读入内存。

Set-Content -Path $inputfile -Value ((Get-Content $inputfile -Raw) -replace $pattern)

编辑 2

好吧,它似乎在 ISE 中有效,但在 powershell 控制台中无效。如果你遇到同样的事情,试试这个。

$pattern = '(?s)\s+<category>Games</category>\r?\n\s+</game>'

Set-Content -Path $inputfile -Value ((Get-Content $inputfile -Raw) -replace $pattern)

推荐阅读