我正在尝试用另一个多行文本替换多行文本。然而,没有任何尝试似乎奏效。未找到搜索的文本。
在搜索到的目录中有一些包含搜索到的文本的 .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/