基幹システムからデータを抽出すると、固定長のデータになっていることがあります。
特に汎用系のシステム、君だよ、君。
まぁそんな時代遅れ?ともとらえられがちな固定長データですが、シンプルなデータ構造のため、構造化されたCSVやxml、JSONといったオープン系の形式よりもデータ容量が少なくて済む、なんてメリットもあります。
しかし、どちらがいい悪いという話ではないんですが、二次利用の容易さという面で見ると、やはり構造化されたデータに軍配があがあります。
そこで今回は、PowerShellを使って固定長のデータをPsObjectに変換するスクリプトを紹介します。
PsObjectになってしまえばこちらのもの。
後は、PowerShellを使ってCSVでもxmlでもjsonでも好きな形式に変換できます。
いつものごとく、文字コードの考慮やエラー処理などは、作り込んでいないので、あくまできっかけとして使っていただければと思います。
(このブログのソースは全体的にそういうものですので悪しからず)
環境
PowerShell5.1
事前に用意するもの
固定長のデータ
PsObjectに変換したい固定長のデータをご準備ください。
区切りの定義
CSV形式でname,start,lengthの3つの項目を定義してください。
name:項目の名前
start:項目の開始位置(文字数単位)
length:項目の長さ(文字数単位)
例
name,start,length 生年月日,0,8 名前,8,10 出身地,18,30
※今回の場合どちらも文字コードはSJIS固定とします。
コード
下記のコードを Import-FixedFile.ps1 として保存します(ファイル名はなんでもいいです)。
スクリプトのパラメタとして、定義ファイルと固定長ファイルのファイルパスを与えます。
#固定長のデータをdefineファイルの定義に従って分割して #psオブジェクトとして返す。 param([parameter(mandatory)][string]$defineFilePath,[parameter(mandatory)][string]$fixedFilePath) $psobjects=@() $defCsv=import-csv -Path $defineFilePath -Encoding Default Get-Content -Encoding Default $fixedFilePath| %{ $object=New-Object psobject foreach($def in $defCsv){ $object|Add-Member -MemberType NoteProperty -Name $def.name -Value $_.substring($def.start,$def.length) } $psobjects+=$object } return $psobjects
例
テストデータ
fixeddatasample.txt(固定長データ)
19881203山田太郎 東京都千代田区丸の内 19740212城之内次郎 千葉県千葉市花見川区 19620924範馬勇次郎 栃木県宇都宮市鶴田町
definesample.txt(定義データ)
name,start,length 生年月日,0,8 名前,8,10 出身地,18,30
結果
$data= (.\Import-FixedFile.ps1 -defineFilePath .\definesample.txt -fixedFilePath '.\fixeddatasample.txt') $data
結果
生年月日名前出身地 --------- 19881203 山田太郎 東京都千代田区丸の内 19740212 城之内次郎 千葉県千葉市花見川区 19620924 範馬勇次郎 栃木県宇都宮市鶴田町
CSVに変換する
PsObjectをCSVで出力するときは、Export-Csvコマンドレットを使えば簡単にできます。
なお、-NoTypeInformationオプションを付与しないと、余計な情報が1行目に入り込んでしまうので注意が必要です。
$data|export-csv -Encoding Default -NoTypeInformation -path .\export.csv
出力結果
Excelで開くとわかりませんが、デフォルトだと、ダブルクォーテーションで囲まれて出力されます。
このようにPsObjectであれば簡単にCSV形式に変更することができます。
そしてJSONへ
また、CSVだけではなく、JSON等にも変換することもできます。
$data|ConvertTo-json
#出力結果 [ { "生年月日": "19881203", "名前": "山田太郎 ", "出身地": "東京都千代田区丸の内 " }, { "生年月日": "19740212", "名前": "城之内次郎 ", "出身地": "千葉県千葉市花見川区 " }, { "生年月日": "19620924", "名前": "範馬勇次郎 ", "出身地": "栃木県宇都宮市鶴田町 " } ]
さらにxmlへ・・・
ConvertTo-Xmlコマンドレットでxmlへ変換も簡単です。
($data|ConvertTo-xml).OuterXml
##出力結果 <?xml version="1.0" encoding="utf-8"?><Objects><Object Type="System.Management.Automation.PSCustomObject"><Property Name=" 生年月日" Type="System.String">19881203</Property><Property Name="名前" Type="System.String">山田太郎 </Property><Property Name="出身地" Type="System.String">東京都千代田区丸の内 </Property></Object><Object Type="System.Management.Automation.PSCustomObject"><Property Name="生年月日" Type="System.String">19740212</Property><Property Name="名前" Type="System.String">城之内次郎 </Property><Property Name="出身地" Type="System.String">千葉県千葉市花見川区 </Property></Object><Object Type="System.Management.Automation.PSCustomObject"><Property Name="生年月日" Type="System.String">19620924</Property><Property Name="名前" Type="System.String">範馬勇次郎 </Property><Property Name="出身地" Type="System.String">栃木県宇都宮市鶴田町 </Property></Object></Objects>
終わりに
PowerShellを使って固定長データをPsObjectへ変換するスクリプトの紹介でした。
固定長の場合、単純な故にデータ構造をこちらが用意しないといけない点が少し面倒ですが、一度PsObjectに変換してしまえば、後は煮るなり焼くなり簡単に料理することができるということがおわかりいただけた(?)かと思います
これを使いこなせればもう固定長なんてこわくない!!知らんけど。
でも固定長と一緒に汎用機系でよく出てくるワードに「文字コード」という壁もあったりするので同時にぶち当たることもありますね。
そのためスクリプトだけで問題を一挙に解決できるかどうかは、わかりません。
それでもこのスクリプトが固定長を扱う際のひとつの道しるべになればいいなぁ・・・
ここまでお読みいただき、ありがとうございました。