適材適所

システム屋のくらげが気ままに書いているブログです。PowerShellやVBAなどプログラミング系の話をメインに書いています。

MENU

PowerShellでテキストファイルの文字列の置換をするときは文字コードに気を付けて!

PowerShellでテキストファイルの文字列を置換したい!!

PowerShellでテキストファイルの文字列を置換する際の覚書です。

大量のテキストファイルの特定の文字列だけを置換したいという、

地味ながらいざ手作業でやろうとすると面倒な作業。

PowerShellを使えばコマンドひとつで一瞬でできる、と思っていたのですが、

どうもそうでもないので、しょうがなくちょっとしたパイプラインを使って実現したっていうお話です。

ファイル内容の置換はコマンドはない・・・?

私も全てのコマンドレッドを知っているわけではないのですが、

この記事を書いている時点(2019年7月時点)では一発でできるコマンドレットは存在しない雰囲気でした。

というわけでGet-ContentコマンドレットとOut-Fileコマンドレッドを組み合わせて実現します。

 
$rep1='置換前の文字列'
$rep2='置換後の文字列'
$fileContets=(Get-Content $file -Encoding $enc) -replace $rep1,$rep2
Out-File -FilePath $file -InputObject $fileContents  -Encoding $enc

$rep1は置換前の文字列を、$rep2は置換後の文字列をそれぞれ指定します。

Get-Contentコマンドレッドでファイルの中身を取得しつつ、-replace演算子で中身の置換を行います。

結果を$fileContets変数に格納し、Out-Fileコマンドレットでファイルに出力しています。

そして、ここで肝になるのが、Get-ContentコマンドレットでもOut-Fileコマンドレットでも-Encodingオプションを使って、文字コードの指定を行っているところです。

どハマりポイント

Get-Contentのときも、Out-Fileのときも、テキストファイルの文字コードをちゃんと意識する必要があります。

PowerShellのデフォルトの文字コードはUTF8です。

そのため、テキストファイルがUTF8で書かれているなら問題ないのですが、

他の文字コードで書かれたテキストファイルの時は要注意です。

特にWindowsのメモ帳で編集したテキストファイルを保存するときは

デフォルトの文字コードShift-JISでファイルが保存されるので注意が必要です。

恨めしや文字コード

なぜ日本語はこうも難しいのでしょう。

システムではそれが文字コードという形になってシステム担当者に襲い掛かります。

日本語のデータを扱う上で、文字コードはいつでもつきまといます。

過去何度文字コードに泣かされたことか・・・。

今回のもそうですが、テキストファイルを扱うコマンドレッドでテキストを扱う場合は必ず文字コードを意識する必要があります。

例えば、一見何の変哲もないテキストファイルがあったとします。

f:id:shinmai_papa:20191125131257p:plain

これをGet-Contentコマンドレッドで中身を確認すると・・・。

PS C:\> Get-Content .\utf8.txt
縺

このようになってしまいます。 実はこのテキストファイル、文字コードをBOM無しUTF8で保存してあります。

Get-Contentのデフォルト文字コードは、Shift-JIS。(Powershell6.0からはBOM無しUTF8らしいです。)

(Get-Content (Microsoft.PowerShell.Management) - PowerShell | Microsoft Docs)

(PowerShell 6.0からファイル出力に関わるエンコーディングが変わります - しばたテックブログ)

ファイルのダンプを見てみると・・・

f:id:shinmai_papa:20191125133643p:plain

こんな感じで保存されています。

「E3 81 82」はUTF8で「あ」です。

文字コードを意識しないと、Get-Contentコマンドレッドが全然違う文字として認識してしまいます。

そうすると意図した結果が得られません。

恨めしや、文字コード。

ちゃんと文字コードを意識してコマンドレッドを実行する

対象のテキストファイルの文字コードを把握して、先ほどのコードを実行する必要があります。

もし、対象のファイルの文字コードがわからない・・・

という時は、このようにします。

 
#ファイルの文字コードを調べる
$file='ファイルのパス'
(New-Object System.IO.StreamReader($file)).CurrentEncoding

え?ちょっと待って?

このオブジェクトをOut-Fileパラメタの-Encodingに素直に渡せば何にも悩む必要なくない?

と私にも思っていた時期がありました。

そうは問屋が卸さず。

Out-FileコマンドレッドのEncodingパラメータはString型でValidateSetが unknown,string,unicode,bigendianunicode,utf8,utf7,utf32,ascii,default,oem に制限されており、このコマンドで出力される結果は、うまく渡せないようです・・・。

うーん。残念。

終わりに

PowerShellでテキストファイルの内容を置換する際の注意点について解説してみました。

テキストファイルの中身の置換なんて需要がありそうなものですが、

まだコマンドレットが用意されていないなんて・・・。

この要件を満たす、便利なコマンドレッドが登場することを願って終わりにしたいと思います。

ここまでお読みいただき、ありがとうございました。