Ric*_*ard 8 regex powershell perl replace text-files
我试图在一个非常大的文本文件30Mb +中替换600个不同的字符串.我现在正在构建一个执行此操作的脚本; 以下问题:
脚本:
$string = gc $filePath
$string | % {
$_ -replace 'something0','somethingelse0' `
-replace 'something1','somethingelse1' `
-replace 'something2','somethingelse2' `
-replace 'something3','somethingelse3' `
-replace 'something4','somethingelse4' `
-replace 'something5','somethingelse5' `
...
(600 More Lines...)
...
}
$string | ac "C:\log.txt"
Run Code Online (Sandbox Code Playgroud)
但是,由于这将检查每行600次,并且文本文件中有超过150,000多行,这意味着需要大量的处理时间.
有没有比这更有效的更好的替代方案?
干杯,对此有任何建议.
结合Adi Inbar答案中的哈希技术和Keith Hill对另一个最近问题的答案的匹配评估器,以下是如何在PowerShell中执行替换:
# Build hashtable of search and replace values.
$replacements = @{
'something0' = 'somethingelse0'
'something1' = 'somethingelse1'
'something2' = 'somethingelse2'
'something3' = 'somethingelse3'
'something4' = 'somethingelse4'
'something5' = 'somethingelse5'
'X:\Group_14\DACU' = '\\DACU$'
'.*[^xyz]' = 'oO{xyz}'
'moresomethings' = 'moresomethingelses'
}
# Join all (escaped) keys from the hashtable into one regular expression.
[regex]$r = @($replacements.Keys | foreach { [regex]::Escape( $_ ) }) -join '|'
[scriptblock]$matchEval = { param( [Text.RegularExpressions.Match]$matchInfo )
# Return replacement value for each matched value.
$matchedValue = $matchInfo.Groups[0].Value
$replacements[$matchedValue]
}
# Perform replace over every line in the file and append to log.
Get-Content $filePath |
foreach { $r.Replace( $_, $matchEval ) } |
Add-Content 'C:\log.txt'
Run Code Online (Sandbox Code Playgroud)
那么,您的意思是您想替换 150,000 行中的每行中的 600 个字符串中的任何一个,并且您希望每行运行一个替换操作?
是的,有一种方法可以做到,但在 PowerShell 中没有,至少我想不出一个方法。它可以在 Perl 中完成。
方法:
问题:
令人沮丧的是,PowerShell 没有在正则表达式替换调用之外公开匹配变量。它不适用于-replace运算符,也不适用于[regex]::replace。
在 Perl 中,您可以这样做,例如:
$string =~ s/(1|2|3)/@{[$1 + 5]}/g;
Run Code Online (Sandbox Code Playgroud)
这会将整个字符串中的数字 1、2 和 3 加 5,因此如果字符串是“1224526123 [2] [6]”,它就会变成“6774576678 [7] [6]”。
但是,在 PowerShell 中,这两种方法都失败了:
$string -replace '(1|2|3)',"$($1 + 5)"
[regex]::replace($string,'(1|2|3)',"$($1 + 5)")
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,$1 的计算结果为 null,表达式计算结果为普通的旧 5。替换中的匹配变量仅在结果字符串中有意义,即单引号字符串或双引号字符串的计算结果。它们基本上只是看起来像匹配变量的反向引用。当然,您可以在双引号字符串中的数字之前引用$,因此它将评估为相应的匹配组,但这违背了目的 - 它不能参与表达式。
解决方案:
[此答案已从原始答案中修改。它已被格式化以适合具有正则表达式元字符的匹配字符串。当然还有你的电视屏幕。]
如果您可以接受使用另一种语言,那么下面的 Perl 脚本就像一个魅力:
$filePath = $ARGV[0]; # Or hard-code it or whatever
open INPUT, "< $filePath";
open OUTPUT, '> C:\log.txt';
%replacements = (
'something0' => 'somethingelse0',
'something1' => 'somethingelse1',
'something2' => 'somethingelse2',
'something3' => 'somethingelse3',
'something4' => 'somethingelse4',
'something5' => 'somethingelse5',
'X:\Group_14\DACU' => '\\DACU$',
'.*[^xyz]' => 'oO{xyz}',
'moresomethings' => 'moresomethingelses'
);
foreach (keys %replacements) {
push @strings, qr/\Q$_\E/;
$replacements{$_} =~ s/\\/\\\\/g;
}
$pattern = join '|', @strings;
while (<INPUT>) {
s/($pattern)/$replacements{$1}/g;
print OUTPUT;
}
close INPUT;
close OUTPUT;
Run Code Online (Sandbox Code Playgroud)
它搜索散列的键(=> 的左侧),并用相应的值替换它们。这是发生了什么:
顺便说一句,您可能已经注意到原始脚本中的其他一些修改。在我最近的 PowerShell 踢球过程中,我的 Perl 收集了一些灰尘,再看一看,我发现有几件事可以做得更好。
while (<INPUT>)一次读取一行文件。比将整个 150,000 行读入数组要明智得多,尤其是当您的目标是效率时。@{[$replacements{$1}]}为$replacements{$1}. Perl 没有像 PowerShell 的$()那样的插入表达式的内置方法,因此使用@{[ ]}作为一种解决方法 - 它创建一个包含表达式的一个元素的文字数组。但我意识到,如果表达式只是一个标量变量,则没有必要(我将它作为初始测试的保留,在那里我将计算应用于$1匹配变量)。| 归档时间: |
|
| 查看次数: |
11695 次 |
| 最近记录: |