替换PowerShell中的`,\r\n`

4
我正在尝试修复一个CSV文件,在文件的末尾有一个,\r\n。无论我做什么,它似乎都没有任何作用。我尝试将表达式放在[]中,这使得它替换了每一个逗号。这意味着问题在于它不能匹配换行符。
我已经使用Sublime Text将文件保存为Windows行结束符,并尝试了\r\n\n\r\n这两种变化。
(Get-Content file.txt) | ForEach-Object { $_ -replace '\,\r\n', [System.Environmen
t]::NewLine } | Set-Content file2.txt

我正在使用 PowerShell 版本 5.1.15063.413


2
Get-Content file.txt | ForEach-Object { $_.TrimEnd(',') } | Set-Content file2.txt ? or in short form gc file.txt | % TrimEnd ',' | sc file2.txt - TessellatingHeckler
2个回答

7

PowerShell原来是相当......特别的。

Get-Content默认返回一个字符串数组。它查找所有换行字符,并使用它们将输入拆分成该数组。这意味着没有换行符可供正则表达式匹配。

稍微变化一下,使用-Raw参数的命令解决了我的问题。

(Get-Content file.txt -Raw).replace(",`r`n", [System.Environment]::NewLine) | Set-Content file2.txt

2
对于仍然使用PowerShell v2的人来说,-Raw参数是不可用的。相反,他们可以读取数组,并使用(Get-Content file.txt) -join "\n"`重新连接它。 - TheMadTechnician

2
实际上,Get-Content默认按行读取并发出输入文件的内容,包括任何风格的换行符——CRLF、LF、CR——并将其剥离。

虽然这种行为可能会让人感到陌生,但通常有助于在管道中处理文件。

正如您的答案所示,-Raw可以用于完整地读取文件,作为一个单独的、多行的字符串,这可以带来很大的性能优势。

举个例子,结合基于正则表达式的 -replace 操作符 对输入 数组每个元素 进行操作的能力,逐行 阅读可以提供的便利(但如果您的文件具有 LF (\n) 结尾,并且您正在选择性地寻找以 , 为前缀的流氓 CRLF (\r\n) 行结尾,则无济于事):
# Convenient, but can be made faster with -ReadCount 0 - see below.
@(Get-Content file.txt) -replace ',$' | Set-Content file2.txt

注意:使用数组子表达式运算符 @(...),可以确保Get-Content调用即使文件只有一行,也会输出一个数组。
正则表达式锚点$匹配每个输入字符串(行)的结尾,从而在每行中删除末尾的逗号,如果存在的话。

Get-Content性能笔记:

如上所示,-Raw是迄今为止最快的读取文本文件的方式,但是它的设计是作为单个多行字符串

默认情况下,逐行读取是很慢的,这主要是因为PowerShell会使用元数据[1]装饰每一行输出(在-Raw的情况下,由于只有一个输出字符串,这只会发生一次)。

然而,您可以通过使用-ReadCount参数以批量读取行 - 给定大小的行数组来加快速度,在这种情况下,仅对每个数组进行装饰,而不是每个单独的行。 -ReadCount 0所有行读入单个数组中。

注意:

  • -ReadCount changes the streaming behavior in the pipeline: Each array is then sent as a whole through the pipeline, which the receiving command needs to be plan for, typically by performing its own enumeration of the array received, such as with a foreach loop.

  • By contrast, using -ReadCount 0 in the context of an expression results in no behavioral difference, which means that it can be used as a simple performance optimization that requires no other parts of the expression to accommodate it; using an expression with a -replace operation as an example:

    # Read all lines directly into an array, with -ReadCount 0,
    # instead of more slowly letting PowerShell stream the lines 
    # (emit them one by one) and then collect them in an array for you.
    # The -replace operator then acts on each element of the array.
    (Get-Content -ReadCount 0 file.txt) -replace ',$'
    
注意:在这种情况下,@(...) 是不必要的,因为-ReadCount 0始终会生成一个数组,即使是单行文件也是如此。
一种更好的逐行处理的替代方案 - 虽然它不能直接用作表达式的一部分 - 是使用-switch语句-File参数 - 有关详细信息,请参见此答案
这些元数据以 ETS(扩展类型系统) 属性的形式提供,其中特别提供有关源文件的行号和路径的信息。将 Get-Content 调用管道到 | Format-List -Force 以查看这些属性。虽然这些额外信息可能很有帮助,但附加它们的性能影响是明显的。考虑到通常情况下并不需要这些信息,因此至少应该提供一个选择退出的选项:请参见 GitHub问题#7537

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接