【问题标题】:Replacing `,\r\n` in PowerShell在 PowerShell 中替换 `,\r\n`
【发布时间】:2021-11-20 23:25:25
【问题描述】:

我正在尝试修复一个结尾有 ,\r\n 的 CSV 文件。不管我做什么,它根本没有做任何事情。我尝试将表达式放在[] 中,这使它替换了每个逗号。这意味着问题在于它无法匹配换行符。

我使用 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

【问题讨论】:

  • Get-Content file.txt | ForEach-Object { $_.TrimEnd(',') } | Set-Content file2.txt ?或简称gc file.txt | % TrimEnd ',' | sc file2.txt

标签: powershell powershell-5.0


【解决方案1】:

PowerShell 原来是相当... 特殊

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

使用-Raw 参数对该命令稍作修改解决了我的问题。

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

【讨论】:

  • 对于仍然停留在 PowerShell v2 上的人,-Raw 参数不可用。相反,他们可以做的是读取数组,然后用(Get-Content file.txt) -join "`n" 重新加入它
【解决方案2】:

确实,Get-Content 默认情况下逐行读取并发出输入文件的内容,并带有任何风格的换行符 - CRLF、LF、CR - 已剥离

虽然该行为可能不熟悉,但对于处理管道中的文件通常有帮助

正如your answer 所示,-Raw 可用于读取文件完整,而不是作为单行多行字符串 - 这可以提供巨大的性能优势

举例说明逐行阅读可以提供的便利,结合基于正则表达式的-replace operator对输入 array每个元素 进行操作的能力(如果您的文件具有 LF (\n) 结尾并且您正在选择性地寻找流氓 CRLF (@987654335 @) 以, 开头的行尾,但这无济于事):

# Convenient, but can be made faster with -ReadCount 0 - see below.
@(Get-Content file.txt) -replace ',$' | Set-Content file2.txt

注意:@(...)array-subexpression operator,用于确保Get-Content 调用也输出一个数组,即使文件恰好只有一个 行。

正则表达式锚$ 匹配每个输入字符串(行)的结尾,实际上从每行中删除尾随,如果存在。 p>


Get-Content 性能说明

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

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

但是,您可以通过批量读取行来加快速度 - 给定大小的行数组 - 使用 -ReadCount 参数,在这种情况下,只有每个阵列,而不是个别的线条,被装饰。 -ReadCount 0所有行读入单个数组。

注意:

  • -ReadCount 改变了流水线在管道中的行为:然后每个数组作为一个整体通过管道发送,这需要计划接收命令,通常通过对接收到的数组执行其自己的枚举,例如使用foreach loop

  • 相比之下,在表达式的上下文中使用-ReadCount 0会导致没有的行为差异,这意味着它可以被使用作为一种简单的性能优化,不需要表达式的其他部分来适应它;以带有-replace 操作的表达式为例:

    # 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 总是 发出一个数组,即使对于单行文件也是如此。支持>

性能更好的逐行处理替代方案 - 虽然它不能直接用作 表达式 的一部分 - 是使用 @ 987654327@ 与 -File 参数 - 详情请参阅 this answer


[1] 此元数据以ETS (Extended Type System) 属性的形式提供,主要提供有关行号和原始文件路径的信息。通过管道将Get-Content 调用| Format-List -Force 以查看这些属性。虽然这些额外信息可能会有所帮助,但附加它对性能的影响是显而易见的。鉴于这些信息通常不需要,至少有一个选择退出会有所帮助:请参阅GitHub issue #7537

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-04
    • 2013-03-22
    • 1970-01-01
    • 2015-07-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 2011-07-23
    相关资源
    最近更新 更多