PowerShell 6で、Shift_JISのCSVをImport-Csvで読み込んだら文字化けした



PowerShell 4で作ったShift_JIS(シフトJIS)のCSVを読み込むスクリプトを、PowerShell 6で動かしたら文字化けした話。

結論としては、下記のようにすればOK。

> Import-Csv -Encoding ([System.Text.Encoding]::GetEncoding(932)) path_to_csv_file

現象

PowerShell 4では、このページにあるように、Import-Csvコマンドレットのオプションとして、-Encoding defaultを付ければよかった。

ところが、PowerShell 6では上手くいかない。

例えば、下記のようなshift-jisのCSVがある。

名前,年齢
田中,20

山田,10

これを、-Encoding defaultオプションで読み込むと、

> Import-Csv -Encoding default ./test.csv                      
O N
---- ----
c 20  

Rc 10  

このように文字化けする具合だ。

原因

まず、「default」がutf-8に変わったのが原因のようだ。

.NET Framework クラスライブラリーの、System.Text名前空間の、Encodingクラスの、Defaultプロパティーを確認した。


> [System.Text.Encoding]::Default

BodyName          : utf-8
EncodingName      : Unicode (UTF-8)
HeaderName        : utf-8
WebName           : utf-8
WindowsCodePage   : 1200
IsBrowserDisplay  : True
IsBrowserSave     : True
IsMailNewsDisplay : True
IsMailNewsSave    : True
IsSingleByte      : False
EncoderFallback   : System.Text.EncoderReplacementFallback
DecoderFallback   : System.Text.DecoderReplacementFallback
IsReadOnly        : True
CodePage          : 65001

PowerShell 4では、-Encoding defaultでshift-jisとして読み込んでいたが、PowerShell 6では、utf-8として読み込まれるため、文字化けしたと思われる。

対処

-Encodingオプションの引数に、shift-jisを指定すればよい。

このページに、
-Encodingパラメーターは全てSystem.Text.Encoding型に統一されます。
とある。ヘルプを見てみると、確かにEncoding型を要求するようだ。


> Get-Help Import-Csv

Import-Csv [[-Path] <string[]>] [[-Delimiter] <char>] [-LiteralPath <string[]>] [-Header <string[]>] [-Encoding <Encoding>]  [<CommonParameters>]

Encodingクラスのドキュメントを見てみると、GetEncoding メソッドの説明に、
指定したコード ページ ID に関連付けられたエンコーディングを返します。
とあるので、これが使えそうだ。

コード ページ IDについては、このページ
「文字セット」とは正式には「符号化文字集合」と呼ばれ、取り扱う対象となる文字集合を定義して命名と番号付けを行ったものです。例えば「JIS X 208」や「Unicode 4.0」などの名称で定義されています。ソフトウェアベンダーが発行するドキュメントでは「コードページ」と表記されていることが多いです。
とあるので、文字セットに付けられた番号、すなわちUTF-8なら65001、Shift_JISなら932の、おなじみの数値だ。

使用可能なエンコーディングのコード ページ IDは、このページの下の方にある表にまとまっている。

今回は、Shift_JISのCSVを読み込みたいので、932を指定する。
GetEncoding メソッドは、staticメソッドなので、インスタンスを作る必要はなく、下記のようにすれば良い。

> [System.Text.Encoding]::GetEncoding(932)

BodyName          : 
EncodingName      : Japanese (Shift-JIS)
HeaderName        : 
WebName           : shift_jis
WindowsCodePage   : 
IsBrowserDisplay  : 
IsBrowserSave     : 
IsMailNewsDisplay : 
IsMailNewsSave    : 
IsSingleByte      : False
EncoderFallback   : System.Text.InternalEncoderBestFitFallback
DecoderFallback   : System.Text.InternalDecoderBestFitFallback
IsReadOnly        : True

CodePage          : 932

これを、下記のように、一度変数に格納してから、-Encodingオプションの引数に指定してもいいし、

> $shiftJis = [System.Text.Encoding]::GetEncoding(932)
> Import-Csv -Encoding $shiftJis ./test.csv

名前 年齢
-- --
田中 20

山田 10

直接指定して、ワンライナーで書いてもいい。その場合は、括弧でくくる必要がある。

> Import-Csv -Encoding ([System.Text.Encoding]::GetEncoding(932)) ./test.csv

名前 年齢
-- --
田中 20

山田 10

以上で、無事、PowerShell 6で、Shift_JISのCSVをImport-Csvで読み込むことができた。

その他のコマンドレットの文字コード指定

Get-Content、Out-File、Export-Csvなども同様に、文字コードを指定するには、-Encodingオプションの引数に、対応する文字コードのSystem.Text.Encodingを指定する。

下記、Get-Contentの例。

> Get-Content -Encoding ([System.Text.Encoding]::GetEncoding(932)) ./test.csv                                                           
名前,年齢
田中,20

山田,10

文字コードがshift-jisのファイル、test.csvの中身を出力している。
文字化けせずに、出力できている。


下記、Out-Fileの例。
文字コードがshift-jisのファイル、test.csvを読み込み、文字コードがutf-8のファイル、test2.csvとして出力している。


> Get-Content  -Encoding ([System.Text.Encoding]::GetEncoding(932)) ./test.csv | Out-File -Encoding ([System.Text.Encoding]::GetEncoding(65001)) -Path test2.csv

test2.csvを、-Encodingの指定なし(utf-8)でGet-Contentすると、文字化けせずに出力されることが確認できた。

> Get-Content ./test2.csv
   
名前,年齢
田中,20

山田,10


下記、Export-Csvの例。

Export-Csvの入力はPSObjectなので、まず、PSObjectを作成する。


> $obj = New-Object -TypeName PSObject
> $obj | Add-Member -Type NoteProperty -Name "名前" -Value "テスト"
> $obj

名前 
-- 
テスト

下記で、上の$objを、文字コードがshift-jisのファイル、test3.csvとして出力している。

$obj | Export-Csv -Encoding ([System.Text.Encoding]::GetEncoding(932)) -Path test3.csv

shift-jisでImport-Csvすると、文字化けせずに読み込まれることが確認できた。

Import-Csv -Encoding ([System.Text.Encoding]::GetEncoding(932)) ./test3.csv

名前 
-- 
テスト


以上、PowerShell 6で、

  • Shift_JISのCSVファイルを、Import-Csvで文字化けせずに読み込む方法
  • Import-Csv、Get-Content、Out-File、Export-Csvコマンドレットで、文字コードを指定する方法

について、まとめた。

コメント

このブログの人気の投稿

Windowsで、特定のユーザーに特定のサービスの再起動を許可する

PowerShellでイベントログを取得する時、「指定した選択条件に一致するイベントが見つかりませんでした。」が煩わしいのでcatchする