switch文のfileオプションの2つの落とし穴
1つ目 Shift_JISで全角文字が化ける
switch文にはfileオプションがあり、指定したファイルの各行をイテレート処理できる。しかしファイルがShift_JISの時は――
$fname = "test.txt" $txt = @" 1:Shift_JISにおける 2:全角のテスト "@ if(-not (Test-Path $fname)){ ni -Type file $fname >$null } # encoding defaultでshift-jisになる sc $fname -Encoding default $txt # 文字化けする switch -regex -file $fname { "^\d:(.*)" { $matches[1] } } # fileオプションをやめてGet-Contentで取得すればおk switch -regex (gc $fname) { "^\d:(.*)" { $matches[1] } }
これがこうなる。
Shift_JIS??????? ?S?p??e?X?g Shift_JISにおける 全角のテスト
2つ目 $switchが使えない
switch文の内側では、$switchでswitchループのイテレータにアクセスできる。
$switch.currentで現在の値を取得。$switch.movenext()で次の値にイテレータを進める。foreach文における$foreachと同様の機能。
この$switchを『Windows PowerShell In Action』では、switch loop enumerator(スイッチループ列挙子)と呼んでいる。
$switchは便利な機能だが、どうやらfileオプション指定時には利用できない。
$fname = "test.txt" $txt = @" aaa bbb # ccc ddd <# eee fff #> ggg "@ if(-not (Test-Path $fname)) { ni -Type file $fname >$null }
こういうテキストファイルがあって、PowerShell風にコメントアウトした部分を除いて取得したい。
しかし、次のコードは、「null 値の式ではメソッドを呼び出せません」とエラーになる。fileオプション指定時は$switchがnullになる模様。
sc $fname $txt switch -regex -file $fname { '^#' { continue } '^<#' { while($switch.current -notmatch '^#>') { [void]$switch.movenext() } } default { $_ } }
1つ目の落とし穴と同様、fileオプションをやめてGet-Contentを用いればうまくいく
switch -regex (gc $fname) { '^#' { continue } '^<#' { while($switch.current -notmatch '^#>') { [void]$switch.movenext() } } default { $_ } }
aaa bbb ddd ggg