首页 > 解决方案 > PowerShell - 删除文本文件中分隔符之间的多行文本

问题描述

我编辑 XML 文件并使用 PowerShell 在记事本中打开它们并替换文本字符串。给定两个不同的分隔符,开始和停止,在 XML 文件中多次出现,我想完全删除分隔符之间的文本(分隔符是否也被删除对我来说并不重要)。

在下面的示例文本中,我想完全删除开始和结束分隔符之间的文本,但保留它之前和之后的所有文本。

我面临的问题是,每行文本的末尾都有换行符,这使我无法进行简单的操作:

-replace "<!--A6-->.*?<!--A6 end-->", "KEVIN"

起始分隔符:

<!--A6-->

停止分隔符:

<!--A6 end-->

示例文本:

<listItem>
<para>Apple iPhone 6</para>
</listItem>
<listItem>
<para>Apple iPhone 8</para>
</listItem>
<!--A6-->
<listItem>
<para>Apple iPhone X</para>
</listItem>
<!--A6 end-->
</randomList></para>
</levelledPara>
<levelledPara>
<!--A6-->
<title>Available Apple iPhone Colors</title>
<para>The current iPhone model is available in
the follow colors.  You can purchase this model
in store, or online.</para>
<!--A6 end-->
<para>If the color option that you want is out
of stock, you can find them at the following
website link.</para>

当前代码:

$Directory = "C:\Users\hellokevin\Desktop\PSTest"

$FindBook = "Book"

$ReplaceBook = "Novel"

$FindBike = "Bike"

$ReplaceBike = "Bicycle"

Get-ChildItem -Path $Directory -Recurse |
    Select-Object -Expand FullName|
        ForEach-Object {
            (Get-Content $_) -replace $FindBook,$ReplaceBook -replace "<!--A6-->.*?<!--A6 end-->", "KEVIN" |
            Set-Content ($_ + "_new.xml")
        }

任何帮助将不胜感激。作为 PowerShell 的新手,我不知道如何在代码中的每一行末尾考虑换行符。感谢您的关注!

标签: regexxmlpowershellreplace

解决方案


对 XML 文件使用搜索和替换是非常不可取的,应该不惜一切代价避免,因为这样很容易损坏 XML。

有更好的修改 XML 的方法,它们都遵循这个模式:

  • 加载 XML 文档
  • 修改文档树
  • 将 XML 文档写回文件。

对于您的情况(“删除标记之间的节点”),可能如下所示:

  • 加载 XML 文档
  • 按文档顺序查看所有 XML 节点
  • 当我们看到一条显示为“A6”的评论时,设置一个标志以从现在开始删除节点
  • 当我们看到“A6 结束”的评论时,取消设置该标志
  • 收集所有应该删除的节点(在标志打开时出现)
  • 在最后一步中,删除它们
  • 将 XML 文档写回文件。

下面的程序将完全做到这一点(并且也会删除“A6”注释本身):

$doc = New-Object xml
$doc.Load("C:\path\to\your.xml")

$toRemove = @()
$A6flag = $false
foreach ($node in $doc.SelectNodes('//node()')) {
    if ($node.NodeType -eq "Comment") {
        if ($node.Value -eq 'A6') {
            $A6flag = $true
            $toRemove += $node
        } elseif ($node.Value -eq 'A6 end') {
            $A6flag = $false
            $toRemove += $node
        }
    } elseif ($A6flag) {
        $toRemove += $node
    }
}
foreach ($node in $toRemove) {
    [void]$node.ParentNode.RemoveChild($node)
}

$doc.Save("C:\path\to\your_modified.xml")

foreach您也可以在循环内进行字符串替换:

if ($node.NodeType -eq "Text") {
    $node.Value = $node.Value -replace "Apple","APPLE"
}

单打独斗-replace$node.Value安全的。-replace对整个 XML做的不是。


推荐阅读