web-dev-qa-db-ja.com

Powershellを使用して正規表現の結果のサブセクションを置き換える

Powershellを使用すると、次のスニペットのように、正規表現を使用して複雑な文字列をファイルから検索し、それを固定値に置き換える方法を知っています。

_Get-ChildItem  "*.txt" |
Foreach-Object {
    $c = ($_ | Get-Content)
    $c = $c -replace $regexA,'NewText'
    [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
}
_

今、私は正規表現の各一致のsubsectionを置き換える方法を見つけようとしています。これは上記のようなスムーズなステップで実行できますか?または、より大きな正規表現の各一致を抽出し、その中で検索して置換し、その結果を何らかの方法で元のテキストに戻す必要がありますか?

例で明確にするために、次のテストテキストで、次のテキストで "TEST = * 1404"のような14xx番号のインスタンスのみを検索し、14xxを16xxに置き換えたいと仮定します。

_A 2180 1830 12 0 3 3 TEST=C1404
A 900 1830 12 0 3 3 TEST=R1413
A 400 1830 12 0 3 3 TEST=R1411
A 1090 1970 12 0 3 3 TEST=U1400
A 1090 1970 12 0 3 3 TEST=CSA1400
A 1090 1970 12 0 3 3 TEST=CSA1414
A 1090 1970 12 0 3 3 TEST=CSA140
A 1090 1970 12 0 3 3 TEST=CSA14001
A 1090 1970 12 0 3 3 TEST=CSA17001
_

つまり結果のテキストは次のようになります。最初の6行のみが変更されることに注意してください。

_A 2180 1830 12 0 3 3 TEST=C1604
A 900 1830 12 0 3 3 TEST=R1613
A 400 1830 12 0 3 3 TEST=R1611
A 1090 1970 12 0 3 3 TEST=U1600
A 1090 1970 12 0 3 3 TEST=CSA1600
A 1090 1970 12 0 3 3 TEST=CSA1614 <- Second instance of '14' shouldn't change
A 1090 1970 12 0 3 3 TEST=CSA140 <- Shorter numbers shouldn't change
A 1090 1970 12 0 3 3 TEST=CSA14001 <- Longer numbers shouldn't change
A 1090 1970 12 0 3 3 TEST=CSA17001
_

次の正規表現は、置換を行う必要がある大きな文字列を見つける仕事をしているようですが、Powershell(replace?)のどの機能を使用して結果の部分文字列を置換するだけなのかわかりません。また、それが役立つ場合は、より良い正規表現を自由に提案してください。

_$regexA = "\bTEST=\b[A-Za-z]+14\d\d\r"
_

むしろ、「=」と「R」、「C」、「CSA」などの数字の間にある可能性のあるものの完全なリストをハードコーディングする必要はありません。

私は1時間ほど何かに取り組んでおり、正規表現のすべての一致を取得し、その中で検索して14を16に置き換え、元のテキストで古い値と新しい値で置き換えを実行します。 replace($myText,"TEST=CSA1400","TEST=CSA1600")ですが、これは特別なケースをうまくカバーしていないため、うさぎの穴に向かっているように感じます。

18
SSilk

保存する部分式をグループ化する(つまり、括弧で囲む)必要があり、置換文字列の変数$1および$2を介してグループを参照する必要があります。次のようなものを試してください:

$regexA = '( TEST=[A-Za-z]+)14(\d\d)$'

Get-ChildItem '*.txt' | ForEach-Object {
    $c = (Get-Content $_.FullName) -replace $regexA, '${1}16$2' -join "`r`n"
    [IO.File]::WriteAllText($_.FullName, $c)
}
25
Ansgar Wiechers

スクリプトブロックデリゲート(エバリュエーターとも呼ばれる)を使用した例を次に示します。

$regex = [regex]'( TEST=\D+)14(\d{2})\s*$'
$evaluator = { '{0}16{1}' -f $args[0].Groups[1..2] }
filter set-number { $regex.Replace($_, $evaluator) }

foreach ($file in Get-ChildItem  "*.txt")
 {
   ($file | get-content) | set-number | Set-Content $file.FullName
 }

-replace演算子よりも間違いなく複雑ですが、powershell演算子を使用して置換テキストを作成できるため、スクリプトブロックに入れることができるすべてのことができます。

2
mjolinor

これを試して:

Get-ChildItem  "*.txt" |
Foreach-Object {
  $c = $_ | Get-Content | Foreach {$_ -replace '(?<=TEST=\D+)14(?=\d{2}(\D+|$))','16'}
  $c | Out-File $_.FullName -Enc Ascii
}
1
Keith Hill