適材適所

WindowsやPowerShellやネットワーク、IBMなどのシステム系の話やポイ活など気になったことも載せているブログです。

【PowerShell】固定長のデータをPsObjectに変換する~そしてCSVへ~

基幹システムからデータを抽出すると、固定長のデータになっていることがあります。

特に汎用系のシステム、君だよ、君。

まぁそんな時代遅れ?ともとらえられがちな固定長データですが、シンプルなデータ構造のため、構造化された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に変換してしまえば、後は煮るなり焼くなり簡単に料理することができるということがおわかりいただけた(?)かと思います

これを使いこなせればもう固定長なんてこわくない!!知らんけど。

でも固定長と一緒に汎用機系でよく出てくるワードに「文字コード」という壁もあったりするので同時にぶち当たることもありますね。

そのためスクリプトだけで問題を一挙に解決できるかどうかは、わかりません。

それでもこのスクリプトが固定長を扱う際のひとつの道しるべになればいいなぁ・・・

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