正则表达式替换Powershell中的多行

时间:2018-10-15 13:33:40

标签: regex powershell newline

我想用每行末尾的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中准备的正则表达式为this one,可在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时,它会匹配并执行替换。

以下所有变体均失败:

  • <<<<<<<\sHEAD\n\[assembly:没有错误,没有替代
  • <<<<<<<\sHEAD\r\n\[assembly:没有错误,没有替代
  • <<<<<<<\sHEAD r n\[assembly:没有错误,没有替代,写主机将其打印为 <<<<<<<\sHEAD \[assembly:

/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)

我想念什么?为什么不替换呢?

非常感谢

2 个答案:

答案 0 :(得分:1)

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

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

    • 解决方案:使用Get-Content -Raw(PSv3 +)将文件整体 读取为多行字符串。
  • 其次,您提到需要将 regex 换行符(行尾)转义序列(\n)(LF)替换为其 PowerShell 字符串插值副本(`n-请注意,PowerShell使用了`,即 backtick 作为转义字符:

    • 请注意,只有在替换字符串中才有必要,以便在输出中创建实际的,文字的换行符(换行符) -与将正则表达式构造\n用于匹配换行符相反。

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

      • 如果不确定所输入的换行符样式,请使用\r?\n以跨平台兼容的方式匹配换行符
        如果您不在乎输入内容包含哪些特定的换行符,则可以习惯使用此方法,方法是安全的。
    • 因此:

      • 在您的 regex 中,您可以在\r\n`r`n之间选择 ,但请注意:

        • `r`n仅在双引号 "..."字符串中起作用。
        • 通常最好使用文字,单引号字符串存储正则表达式-需要使用\r\n(Windows)/ { {1}}(Unix)/ \n(与平台无关)-这样一来,就不会混淆PowerShell内插字符串的哪些部分以及正则表达式引擎解释了哪些部分。< / li>
      • 在您的替换字符串中,在\r?\n中使用`r`n创建实际的换行符。


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

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

[1]您的调用看起来像.NET method 调用,尽管在这种情况下它可以正常工作,但应避免这种语法混淆:PowerShell cmdlet和函数的调用方式类似于< em> shell 命令:不带括号("..."),并带有空格分隔的参数。

答案 1 :(得分:0)

请参阅以下演示:

$newText = @'
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
'@

$src = @'
<<<<<<< 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
Other lines and second instance
<<<<<<< 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
Some other lines
'@

$src -replace ('<<<<<<< HEAD\s+',
    '\[assembly: AssemblyVersion\("2\.0\.0\.0"\)\]\s+',
    '\[assembly: AssemblyFileVersion\("2\.0\.0\.0"\)\]\s+'+
    '=======\s+'+
    '\[assembly: AssemblyVersion\("1\.1\.0\.0"\)\]\s+',
    '\[assembly: AssemblyFileVersion\("1\.1\.0\.0"\)\]\s+'+
    '>>>>>>> v1_final_release'),$newText

此外,请确保将您的内容读为一个大字符串。可以使用Get-Content $path -Raw[System.IO.File]::ReadAllText($path)来实现。