我编辑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的新手,我不知道如何在代码的每一行末尾添加换行符。感谢您的光临!
注意:
通常,为了进行可靠的处理,应该使用专用的XML解析器来解析XML文本。
在当前的特定情况下,使用正则表达式是一个方便的快捷方式,但要注意的是,它仅在删除行块是自包含元素或元素序列时才有效;如果此假设不成立,则修改将使XML文档无效。
此外,可能还会存在字符编码问题,因为将XML文件读取为文本不会遵循encoding
文件XML声明中可能存在的显式属性-有关详细信息,请参见底部。
也就是说,以下技术适用于修改没有特定形式结构的纯文本文件。
您需要使用s
(SingleLine
)正则表达式选项来确保.
还匹配换行符-如果将这些选项用于行内,则必须将其放在(?...)
正则表达式的开头;也就是说,'(?s)...'
在这种情况下。
[\s\S]
而不是x15.
所建议的方法;此表达式匹配任何为空白字符的字符。或非空格字符,因此匹配任何字符,包括换行符。要完全删除感兴趣的行,还必须匹配前面和后面的newline。
(Get-Content -Raw file.xml) -replace '(?s)\r?\n<!--A6-->.*?<!--A6 end-->\r?\n'
Get-Content -Raw file.xml
将文件作为一个整体读取到内存中(单个字符串)。
Get-Content
在没有BOM的情况下对文件的字符编码进行假设:Windows PowerShell假定为ANSI编码,而PowerShell [Core] v6 +现在明智地假定为UTF-8。由于Get-Content
是读取cmdlet的通用文本文件,因此它不知道encoding
XML输入文件的XML声明中的潜在属性(例如<?xml version="1.0" encoding="ISO-8859-1"?>
)Set-Content
Windows PowerShell中的默认值为ANSI,而无BOM的UTF-8 PowerShell [Core] v6 +为默认值。-Encoding
参数Get-Content
和Set-Content
\r?\n
匹配Windows风格的CRLF换行符和Unix风格的仅LF换行符。
如果不能保证换行不能在感兴趣的行之前/之后,请使用(?:\r?\n)?
代替\r?\n
。
要验证结果字符串仍然是有效的XML文档,只需将命令(或其捕获的结果)强制转换为[xml]
:[xml] ((Get-Content ...) -replace ...)
如果发现文档已损坏,请使用Tomalak的功能完全强大但更复杂的XML解析答案。
如果您使用Get-Content
XML作为文本读取XML文件,并且该文件既没有UTF-8 BOM也没有UTF-16 / UTF-32 BOM,请Get-Content
进行以下假设:它假定Windows PowerShell中为ANSI编码(例如Windows-1252) ,更明智的是,在PowerShell [Core] v6 +中使用UTF-8编码。由于Get-Content
是读取cmdlet的通用文本文件,因此它不知道encoding
XML输入文件的XML声明中的潜在属性。
如果您知道实际的编码,请使用-Encoding
参数进行指定。
-Encoding
与Set-Content
以后使用相同的值来保存文件:在PowerShell中,通常是这样,一旦通过读取文件的cmdlet将数据加载到内存中,就不会保留有关其原始编码的信息,并使用写入文件的cmdlet例如Set-Content
稍后使用其固定的默认编码,该默认编码再次为Windows PowerShell中的ANSI和PowerShell [Core] v6 +中的无BOM的UTF-8。请注意,不幸的是,不同的cmdlet在Windows PowerShell中具有不同的默认值,而PowerShell [Core] v6 +可以一致地默认为UTF-8。
在System.Xml.XmlDocument
.NET类型(其PowerShell的类型加速器[xml]
)提供了强大的XML解析,并使用其.Load()
和.Save()
方法提供了更好的编码支持,如果该文档的XML声明包含一个明确的encoding
属性命名使用的编码:
如果这样的属性存在(例如,<?xml version="1.0" encoding="ISO-8859-1"?>
),两者都.Load()
和.Save()
将履行它。
encoding
属性的输入文件将被正确读取,并以相同的编码保存。encoding
属性中命名的编码反映输入文件的实际编码。否则,如果该文件没有BOM,(BOM-更少)UTF-8被假定,作为使用PowerShell [核心] V6 +的Get-Content
/ Set-Content
-这是合理的,因为这既不具有XML文档encoding
属性,也不是UTF-8或UTF-根据W3C XML建议书,16 BOM应该默认为UTF-8 ;如果文件确实具有BOM表,则只允许使用UTF-8和UTF-16而不在encoding
属性中命名编码,尽管实际上XmlDocument
也可以正确读取带有BOM表的UTF-32文件。
这意味着.Save()
将不会保留不具有encoding
属性的(带有BOM)UTF-16或UTF-32文件的编码,而是创建一个无BOM的UTF-8文件。
如果要检测文件的实际编码-根据其BOM的存在/不存在或encoding
属性(如果存在)来推断,请通过XmlTextReader
实例读取文件:
# Create an XML reader.
$xmlReader = [System.Xml.XmlTextReader]::new(
"$pwd/some.xml" # IMPORTANT: use a FULL PATH
)
# Read past the declaration, which detects the encoding,
# whether via the presence / absence of a BOM or an explicit
# `encoding` attribute.
$null = $xmlReader.MoveToContent()
# Report the detected encoding.
$xmlReader.Encoding
# You can now pass the reader to .Load(), if needed
# See next section for how to *save* with the detected encoding.
$xmlDoc = [xml]::new()
$xmlDoc.Load($xmlReader)
$xmlReader.Close()
如果给定文件不符合规定,并且您知道实际使用的编码和/或要使用给定编码保存(请确保文件不与encoding
属性相矛盾,如果有的话),则可以显式指定编码(等同于-Encoding
与Get-Content
/一起Set-Content
使用,通过使用以给定编码构造的/实例来接受实例的.Load()
/.Save()
方法重载;例如:Stream
StreamReader
StreamWriter
# Get the encoding to use, matching the input file's.
# E.g., if the input file is ISO-8859-1-encoded, but lacks
# an `encoding` attribute in the XML declaration.
$enc = [System.Text.Encoding]::GetEncoding('ISO-8859-1')
# Create a System.Xml.XmlDocument instance.
$xmlDoc = [xml]::new()
# Create a stream reader for the input XML file
# with explicit encoding.
$streamIn = [System.IO.StreamReader]::new(
"$pwd/some.xml", # IMPORTANT: use a FULL PATH
$enc
)
# Read and parse the file.
$xmlDoc.Load($streamIn)
# Close the stream
$streamIn.Close()
# ... process the XML DOM.
# Create a stream *writer* for saving back to the file
# with the same encoding.
$streamOut = [System.IO.StreamWriter]::new(
"$pwd/t.xml", # IMPORTANT: use a FULL PATH
$false, # don't append
$enc # same encoding as above in this case.
)
# Save the XML DOM to the file.
$xmlDoc.Save($streamOut)
# Close the stream
$streamOut.Close()
将文件路径传递给.NET方法的一般警告:始终使用完整路径,因为.NET当前目录的概念通常不同于PowerShell的概念。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句