PowerShell Replaceを使用してテキストを置換する方法[例]

多くの他の言語と同様に、PowerShellは文字列とテキストを扱うことができます。その中でも便利な機能の一つは、PowerShellを使用してファイル内の文字、文字列、さらにはテキストを置換することです。

このチュートリアルでは、PowerShellのreplace()メソッドとPowerShellのreplace演算子の使い方について学びます。このチュートリアルでは基本的な内容から、いくつかの「楽しい」正規表現までカバーします!

始める前に

このチュートリアルのすべての例に従うためには、PowerShellが必要です。このチュートリアルの例ではPowerShell v7.0.2を使用していますが、すべての例はWindows PowerShellでも動作するはずです。

PowerShellを使って文字列を置換する:基本

PowerShellを使用して文字列内の文字を置換する場合は、最も単純なケースの一つです。いくつかの例から始めましょう。

PowerShellで値がhello, worldという文字列があるとします。

$string = 'hello, world'

その文字列内のhelloという文字列をhiという文字列で置換して、$string変数の値をhi, worldにしたいとします。これを実現するために、PowerShellはまず「検索」テキストの場所を見つける必要があります。見つけた後、ユーザーが指定した値でそのテキストを置換します。

Replace()メソッドの使用方法

PowerShellのreplaceコマンドメソッドを使用して、文字列を置換する最も簡単な方法の一つは、以下に示すようにreplace()メソッドを使用することです。replace()メソッドには2つの引数があります。検索する文字列と、見つかったテキストを置換する文字列です。

以下の例では、PowerShellが文字列hello検索し、その文字列を文字列hi置換しています。メソッドは最終結果としてhi, worldを返します。

PS> $string.replace('hello','hi')
hi, world

任意の文字列に対してPowerShellのreplaceメソッドを呼び出すことで、任意のリテラル文字列を別の文字列で置換することができます。文字列が見つからない場合、replace()メソッドは何も返しません。

文字列内のテキストを置換するために、変数に文字列を割り当てる必要はありません。代わりに、'hello world'.replace('hello','hi')のように文字列自体でreplace()メソッドを直接呼び出すことができます。このチュートリアルでは、便宜上変数を使用しています。

文字の削除

文字列内の文字を別の文字列で置換するのではなく、削除したい場合もあります。その場合は、空の文字列を指定することもできます。

PS> $string.replace('hello','')
, world

複数のインスタンスの置換

他の文字列内の文字列を置換するコードを持っていますが、複数の文字列を置換する場合はどうすればよいでしょうか?それも問題ありません。

PowerShellのreplaceメソッドは文字列を返すため、別のインスタンスを置換するためには、元の出力にreplace()メソッドの呼び出しを追加することができます。PowerShellはその後、元の出力に対してreplace()メソッドを呼び出します。

PS> $string.replace('hello','').replace('world','earth')
, earth

必要なだけreplace()メソッド呼び出しを連鎖させることができますが、多くの文字列を置換する場合はreplace演算子を使用することを検討する必要があります。

PowerShellのReplace演算子の使用

テキストを置換するためには、PowerShellの置換文字列メソッドを使用する方法が最も簡単ですが、PowerShellのreplace演算子も使用できます。このreplace演算子は、置換すべき文字列を指定する点でメソッドと似ています。しかし、大きな利点があります。それは、正規表現(regex)を使用して一致する文字列を検索できるという点です(後述)。

上記の例を使って、以下のようにreplace演算子を使用してhellohiに置換することができます。PowerShellは同じ手順を実行します。

PS> $string -replace 'hello','hi'
hi, world

文字の削除

PowerShellのreplace演算子を使用して、文字列から文字を削除することもできます。ただし、replace()メソッドとは異なり、置換する文字列を引数に完全に除外することもできます。この場合も同じ効果が得られます。

PS> $string -replace 'hello',''
, world
PS> $string -replace 'hello'
, world

複数のインスタンスの置換

replace()メソッドと同様に、replace演算子を連鎖させることもできます。replace演算子は以下のように文字列を返すため、次のセクションでは正規表現を使用することでコードがよりスマートになります。

PS> $string -replace 'hello','hi' -replace 'world','earth'
hi, earth

PowerShellのRegex Replaceを使用する

上記のように、PowerShellのreplaceメソッドを使用して文字列を置換することはできますが、制限があります。リテラル文字列のみ使用できます。ワイルドカードや正規表現は使用できません。中級または高度な置換を行う場合は、replace演算子を使用する必要があります。

スクリプトに変数で作成された文字列が含まれているとします。その文字列はhello, worldまたはhi, world.のいずれかである必要があります。システム管理者として悪い日を過ごしたかもしれませんが、値に関係なく文字列をgoodbye, worldに変更したい場合は、次のようにします。

hello, worldhi, worldの両方をgoodbye, worldに変換する必要があります。これを実現するには、正規表現を使用する必要があります。正規表現を使用してテキスト内の特定のパターンをほぼすべてマッチさせることができます。

この例では、正規表現「または」(|)文字を使用して、下記のように必要な両方の文字列に一致させることができます。

PS> 'hello, world' -replace 'hello|hi','goodbye'
goodbye, world
PS> 'hi, world' -replace 'hello|hi','goodbye'   
goodbye, world

文字列を見つけるために正規表現を使い方を学ぶと、ワイルドカード文字列を一致させるためにPowerShellを使用することができます。任意のパターンに一致するワイルドカード文字列を置換することができます。

正規表現文字のエスケープ

上記の正規表現の例では、検索対象の文字列には正規表現の特殊文字は含まれていませんでした。正規表現言語には、一般の文字や数字とは異なる意味で解釈される特定の文字があります。

例えば、文字列内のテキストを置換する必要があるかもしれません。その文字列には、角括弧や疑問符などの正規表現の特殊文字が含まれています。次のように、文字列[hello]goodbyeで置換しようとします。

PS> '[hello], world' -replace '[hello]','goodbye'
[goodbyegoodbyegoodbyegoodbyegoodbye], wgoodbyergoodbyed

これは明らかに意図した結果ではありません。このようなシナリオは、文字列内で正規表現の特殊文字([hello])を使用した場合に発生します。

この問題を回避するには、2つのオプションがあります。それぞれの文字の前にバックスラッシュを追加して特殊文字をエスケープするか、Escape()メソッドを使用することです。

以下では、各特殊文字をバックスラッシュでエスケープした場合の効果が示されています。

PS> '[hello], world' -replace '\[hello\]','goodbye'
goodbye, world

または、より推奨される方法として、正規表現の型のEscape()メソッドを使用してすべての特殊文字を自動的に削除することができます。

PS> '[hello], world' -replace ([regex]::Escape('[hello]')),'goodbye'
goodbye, world

できる限りEscape()メソッドを使用するべきです。それによって、特殊文字を覚える必要がなくなります。

マッチ/キャプチャグループの使用

これまでの例では、このチュートリアルでは、別の文字列で置き換えるためにリテラル文字列を使用してきました。higoodbyeを使用してきました。しかし、PowerShellが見つけた文字列を置き換えるために、1つまたは複数の文字を使用したい場合はどうでしょうか。これには、一致またはキャプチャグループを使用する必要があります。

正規表現には、キャプチャグループとバックリファレンスという概念があります。キャプチャグループを使用すると、他の場所で参照するために文字列をキャプチャできます。PowerShellは、replace演算子を使用してこれらの機能を活用します。

例えば、いくつかの異なる値が含まれる可能性がある文字列があるかもしれません。

'hello world, you sexy beast'
'hi world, now go away'
'hello earth, you are lovely today'

以下のように、文字列の最初の部分と2番目の部分を入れ替えたいとします。

'you sexy beast,hello world'
'now go away,hi world'
'you are lovely today,hello earth'

この操作を行うために、PowerShellはカンマの左側と右側のテキストをすべて見つける必要があります。それがどのテキストであるかを知ったら、それを別のテキストで置き換える必要があります。そのためには、バックリファレンスが必要です。

A backreference is a regex variable (not a PowerShell variable) that represents the text that regex matched. Backreferences in PowerShell are represented with a dollar sign followed by a number indicating the order in which they were matched.

以下に例を示します。

## この文字列は次のようになる場合もあります:
## 'hi, world, now go away'
## 'hello, earth, you are lovely today'
PS> $string = 'hello, world, you sexy beast'
PS> $string -replace '(.*), (.*)','$2,$1'
you sexy beast,hello world

上記の例では、正規表現のキャプチャグループがマッチ(hello world)と(you sexy beast)をカッコで囲んでいるのが見えます。そして、置換のために、hello worldが最初に左から右にマッチしたので、$1がバックリファレンスラベルとして、you sexy beast$2として返されます。

PowerShellがそれぞれのマッチの値を知ったら、これらの参照を置換テキスト内で任意の方法で使用できます。この例では、$2,$1は位置を入れ替えます。

名前付きマッチグループの使用

マッチ値を参照するために$1$2などの数字のプレースホルダを使用したくない場合、ラベルまたは名前も使用できます。左から右に数える必要がある参照が何を意味するかを避けるために、名前を使用することができます。

名前を参照として使用するには、まずマッチ文字列の各マッチに対してラベルを定義する必要があります。それには、キャプチャグループを(?<label><regex>)のように定義する必要があります。ここで、labelは名前であり、<regex>は使用している正規表現です。

名前を定義したら、置換文字列でドル記号を使用し、名前を中括弧で囲んで参照することができます。例えば、${label}です。

このテクニックのデモンストレーションを以下で見ることができます。

PS> $string = 'hello, world, you sexy beast'
PS> $string -replace '(?<First_Part>.*), (?<Second_Part>.*)','${Second_Part},${First_Part}'
you sexy beast,hello, world

結論

学んだ通り、PowerShellの置換演算子はさまざまな方法で文字、テキスト、文字列を置換することができます。単純な置換を行う場合は、replace()メソッドを使用することができますが、より高度なマッチングと置換が必要な場合は常にreplace演算子を使用してください。

Source:
https://adamtheautomator.com/powershell-replace/