Powershell替换多行文本

标签 powershell replace

我正在尝试用另一个多行文本替换多行文本。然而,没有任何尝试似乎奏效。未找到搜索的文本。

在搜索到的目录中有一些包含搜索到的文本的 .xml 文件。

这是一些代码:

Set-Location "D:\path\test"

$file_names = (Get-ChildItem).Name

$oldCode =  @"

       </LinearLayout>


    <TextView
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="0dp"/>


</LinearLayout>
"@

$newCode =  @"
          ANYTHING NEW

       </LinearLayout>


    <TextView
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="0dp"/>


</LinearLayout>
"@

foreach ($name in $file_names)
{
    # None of below code works.

    # Attempt 1: trying to find the code
    Write-Host $name
    $ret_string = (Get-Content -raw -Path $name | Select-String $oldCode -AllMatches | % { $_.matches}).count
    Write-Host $ret_string

    # Attempt 2: trying to actually replace the string
    $fileContent = Get-Content $name -Raw
    Write-Host $fileContent
    $newFileContent = $fileContent -replace $oldCode, $newCode
    Write-Host $newFileContent

    # Attempt 3: another try to replace the string
    ((Get-Content -Path $name -Raw) -replace $oldCode, $newCode) | Set-Content -Path $name
}

Write-Host "Press any key to continue..."
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

(感谢所有帮助,这里是包含测试文件的工作解决方案的链接:https://github.com/Sokrates1989/powershell-multiline-replace)

最佳答案

Select-string-replace两者都采用正则表达式作为搜索字符串。由于一些常见字符在正则表达式中具有特殊含义,因此使用 [Regex]::Escape() 始终是一个好主意。每当您想要与文字字符串精确匹配时,都可以使用此方法。它提供了额外的优势,可以揭示空白(例如与 )和非打印字符(例如 和 )的确切性质。

使用发布的代码,

$oldCode =  [Regex]::Escape(@"

       </LinearLayout>



    <TextView
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="0dp"/>


</LinearLayout>
"@)


PS > $oldCode
\n\ \ \ \ \ \ \ </LinearLayout>\n\n\n\n\ \ \ \ <TextView\n\ \ \ \ \ \ \ \ android:layout_weight="1"\n\ \ \ \ \ \ \ \ android:layout_width="wrap_content"\n\ \ \ \ \ \ \ \ android:layout_height="0dp"/>\n\n\n</LinearLayout>

上面的内容仍然与发布的 $NewCode 不匹配因为第一个 </LinearLayout> 前面有两个额外的空格,因此如果用正则表达式 \s+ 替换出现的一个或多个空白字符,则匹配会更加稳健。 ,它匹配一个或多个空白字符。

此外,如mklement0's answer解释说,根据来源,换行符可以编码为 \n\r\n ,因此两者都可以与表达式 \r?\n 匹配.

因此,使用转义文字字符串,您可以执行以下操作:

PS > $oldcode -replace ( '((\\ )|(\\t))+' , '\s+' ) -replace ( '(\\r)?\\n' , '\r?\n' )
\r?\n\s+</LinearLayout>\r?\n\r?\n\r?\n\r?\n\s+<TextView\r?\n\s+android:layout_weight="1"\r?\n\s+android:layout_width="wrap_content"\r?\n\s+android:layout_height="0dp"/>\r?\n\r?\n\r?\n</LinearLayout>
PS >

当然,您可以结合使用转义符和空格/换行符转换:

$OldCodeRobustRegex =  [Regex]::Escape(@"

       </LinearLayout>



    <TextView
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="0dp"/>


</LinearLayout>
"@)  -replace ( '((\\ )|(\\t))+' , '\s+' ) -replace ( '(\\r)?\\n' , '\r?\n' )

输出:

PS > $OldCodeRobustRegex
\r?\n\s+</LinearLayout>\r?\n\r?\n\r?\n\r?\n\s+<TextView\r?\n\s+android:layout_weight="1"\r?\n\s+android:layout_width="wrap_content"\r?\n\s+android:layout_height="0dp"/>\r?\n\r?\n\r?\n</LinearLayout>
PS >
PS > $NewCode -match $OldCodeRobustRegex
True
PS >

附注

如果可能存在无关的空行(连续的换行符),您可以将换行符替换部分修改为:

 -replace ( '((\\r)?\\n)+' , '(\r?\n)+' )

关于Powershell替换多行文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73930215/

相关文章:

powershell 更新帮助失败

powershell - 将JSON文件上传到Web API

string - 文字替换-字符串和空格

python - 更改 Tkinter 文本小部件中的退格效果

mysql - 在 mysql : what's the alternative? 中弃用 "replace"实用程序

mysql - SQL:搜索/替换,但仅在值第一次出现在记录中时

python - 你能用内部方法完全替换一个对象吗?

c - 从 powershell 调用 vcvarsall.bat 后运行构建脚本

PowerShell 原始 FTP

.net - 在PowerShell中使用WinSCP将整个驱动器上载到服务器,从而跳过所有无法读取的文件和文件夹