つまり、150,000 行ごとに 600 個の文字列のいずれかを置換し、1 行につき 1 つの置換操作を実行したいということですか?
はい、それを行う方法はありますが、PowerShell ではありません。少なくとも私には思いつきません。Perlでできます。
メソッド:
- キーが何かで、値が何か他のものであるハッシュを構築します。
- ハッシュのキーを|で結合します。シンボルを検索し、正規表現で一致グループとして使用します。
- 置換では、キャプチャ グループの一致変数を使用してハッシュから値を取得する式を補間します
問題:
苛立たしいことに、PowerShell は一致変数を正規表現の置換呼び出しの外に公開しません。-replace演算子では機能せず、[ regex]::replaceでは機能しません。
Perl では、たとえば次のように実行できます。
$string =~ s/(1|2|3)/@{[$1 + 5]}/g;
これにより、文字列全体の数字 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)")
どちらの場合も、$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;
ハッシュのキー ( =>の左側) を検索し、それらを対応する値に置き換えます。何が起こっているかは次のとおりです。
- foreachループは、ハッシュのすべての要素を調べて、%replacements ハッシュのキーを含む @strings という配列を作成します。メタ文字は\ Qおよび\ Eを使用して引用され、その結果は正規表現パターンとして使用するために引用されます。 ( qr = 正規表現を引用)。同じパスで、置換文字列のすべてのバックスラッシュを 2 倍にしてエスケープします。
- 次に、配列の要素が|で結合されます。の検索パターンを形成します。必要に応じて$patternにグループ化括弧を含めることもできますが、この方法により、何が起こっているのかがより明確になると思います。
- whileループは、入力ファイルから各行を読み取り、検索パターン内の文字列をハッシュ内の対応する置換文字列に置き換え、その行を出力ファイルに書き込みます。
ところで、元のスクリプトからいくつかの変更が加えられていることに気付いたかもしれません。私の Perl は、最近の PowerShell のキック中にいくらかのほこりを集めました。
while (<INPUT>)
一度に 1 行ずつファイルを読み取ります。特に目標が効率である場合は、150,000 行全体を配列に読み込むよりもはるかに賢明です。
- に簡略化
@{[$replacements{$1}]}
しました$replacements{$1}
。Perl には、PowerShell の$()のような式を補間する組み込みの方法がないため、回避策として@{[ ]}が使用されます。これは、式を含む 1 つの要素のリテラル配列を作成します。しかし、式が単一のスカラー変数である場合は必要ないことに気付きました ( $1マッチ変数に計算を適用した最初のテストからの持ち越しとしてそこに入れました)。
- closeステートメントは厳密には必要ありませんが、ファイルハンドルを明示的に閉じることをお勧めします。
- for の略語をforeachに変更して、PowerShell プログラマーにとってより明確で親しみやすいものにしました。