首页 > 解决方案 > 正则表达式替换powershell中的多行

问题描述

我想在每行末尾用 Windows CRLF 替换以 UTF-8 编码的 AssemblyInfo.cs 中的这些行

<<<<<<< HEAD
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
=======
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
>>>>>>> v1_final_release

通过这些

[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]

为此,我有一个 powershell 脚本,它将解析我的所有文件并进行替换。

我在 regex101 中准备的正则表达式是这个并且适用于 101 :

<<<<<<<\sHEAD\n\[assembly:\sAssemblyVersion\("2\.0\.0\.0"\)\]\n\[assembly:\sAssemblyFileVersion\("2\.0\.0\.0"\)\]\n=======\n\[assembly:\sAssemblyVersion\("1\.1\.0\.0"\)\]\n\[assembly: AssemblyFileVersion\("1\.1\.0\.0"\)\]\n>>>>>>>\sv1_final_release

我无法使 -replace 在新线路上工作。但是当仅定位时<<<<<<<\sHEAD,它匹配并执行替换。

以下所有变体均失败:

这不是关于/gm(*CRLF)

我的 powershell 信息说明:

$ConflictVersionRegex = "<<<<<<<\sHEAD\n\[assembly:\sAssemblyVersion\(`"2\.0\.0\.0`"\)\]\n\[assembly:\sAssemblyFileVersion\(`"2\.0\.0\.0`"\)\]\n=======\n\[assembly:\sAssemblyVersion\(`"1\.1\.0\.0`"\)\]\n\[assembly: AssemblyFileVersion\(`"1\.1\.0\.0`"\)\]\n>>>>>>>\sv1_final_release" 
$ConflictVersionRegexTest = "<<<<<<<\sHEAD`r`n\[assembly:" 
$fileContent = Get-Content($filePath)   
$filecontent = $filecontent -replace $ConflictVersionRegexTest, $AssemblyNewVersion
[System.IO.File]::WriteAllLines($filePath, $fileContent, $Utf8NoBomEncoding)

我错过了什么?为什么不替换?

非常感谢

标签: regexpowershellnewline

解决方案


根据 Poutrathor(OP)的反馈,存在两个问题:

  • 主要问题Get-Content($filePath)(应该写为
    Get-Content $filePath[1]逐行读取文件,当在变量中捕获时会产生一个行数组。然后单独
    -replace对每个输入行进行操作,这意味着跨行正则表达式不会匹配任何内容。

    • 解决方案:使用Get-Content -Raw(PSv3+) 将文件作为一个整体读入单个多行字符串。
  • 其次,您提到需要将正则表达式换行符(行尾)转义序列(\n)(LF)替换为其PowerShell字符串插值对应项(`n -请注意,PowerShell使用`引号作为转义字符:

    • 请注意,这仅在替换字符串中是必需的,以便在输出上创建实际的文字换行符(换行符)- 而不是使用正则表达式构造来匹配换行符。\n

    • 但是,在 Windows 上,换行符通常是 CRLF序列,即 CR ( \r, `r) 紧跟 LF ( \n/ `n) - 即\r\n/`r`n - 而在类 Unix 平台上它们只是LF, \n/`n

      • 如果您不确定给定输入具有哪种样式的换行符,请使用\r?\n以跨平台兼容的方式匹配换行符
        如果您不关心输入有哪些特定的换行符,那么按照习惯,可以安全地有条不紊地使用。
    • 所以:

      • 在您的regex中,在您的情况下,您可以在and之间进行选择,请注意:\r\n`r`n

        • `r`n仅适用于双引号 "..."字符串。
        • 通常最好使用文字、单引号字符串来存储正则表达式——这需要使用\r\n(Windows)/ \n(Unix)/ \r?\n(平台不可知论) ——这样就不会混淆 PowerShell 的哪些部分在前面与. 正则表达式引擎解释了哪些部分。
      • 在您的替换字符串中,使用`r`ninside"..."创建实际的换行符。


作为使用转义序列表示换行符的替代方法,您可以使用here-strings方便地定义具有实际换行符(换行符)的多行字符串,如Paweł Dyl 的回答所示,但有一个警告

  • Here-strings 总是具有与封闭脚本文件相同的换行符样式,这意味着:
    • 仅当输入恰好与脚本文件具有相同样式的换行符时,基于此处字符串的正则表达式才会匹配。
    • 基于 here-string 的替换字符串将始终使用脚本文件的换行符样式。

[1] 您的调用看起来像一个 .NET方法调用,虽然它恰好在这种情况下工作,但应避免此类语法混淆:PowerShell cmdlet 和函数像shell命令一样被调用:不带括号 ( (...)) 并使用空格分隔的参数。


推荐阅读