適材適所

PowerShellやVBAなどプログラミング系の話多めで

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

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

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

まぁそんな時代遅れ?ともとらえられがちな固定長データですが、

シンプルなデータ構造のため、構造化されたCSVやxml、JSONといった

オープン系の形式よりもデータ容量が少なくて済む、なんてメリットもあります。

しかし、どちらがいい悪いという話ではないんですが、

二次利用の容易さという面で見ると、やはり構造化されたデータに軍配があがあります。

そこで今回は、PowerShellを使って固定長のデータをPsObjectに変換するスクリプトを紹介します。

PsObjectになってしまえばこちらのもの。

後は、PowerShellを使ってCSVでもxmlでもjsonでも好きな形式に変換できます。

いつものごとく、文字コードの考慮やエラー処理などは、作り込んでいないので、

あくまできっかけとして使っていただければと思います。

(このブログのソースは全体的にそういうものですので悪しからず)

環境

PS C:\> $PSVersionTable['PSVersion']
MajorMinorBuildRevision
-----------------------
5118362145

事前に用意するもの

固定長のデータ

PsObjectに変換したい固定長のデータ。

区切りの定義

CSV形式でname,start,lengthの3つの項目を定義してください。

name:項目の名前

start:項目の開始位置(文字数単位)

length:項目の長さ(文字数単位)

name,start,length
生年月日,0,8
名前,8,10
出身地,18,30

※どちらも文字コードはSJIS固定です。

コード

スクリプトのパラメタとして、定義ファイルと固定長ファイルのファイルパスを与えます。

 
#固定長のデータを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

結果

PS C:\>$data= (.\Import-FixedFile.ps1 -defineFilePath .\definesample.txt -fixedFilePath '.\fixeddatasample.txt')

PS C:\> $data

生年月日名前出身地
---------
19881203 山田太郎       東京都千代田区丸の内                    
19740212 城之内次郎      千葉県千葉市花見川区                    
19620924 範馬勇次郎      栃木県宇都宮市鶴田町            

CSVに変換する

PsObjectをCSVで出力するときは、Export-Csvコマンドレットを使えば簡単にできます。

なお、-NoTypeInformationオプションを付与しないと、余計な情報が1行目に入り込んでしまうので注意が必要です。

PS C:\> $data|export-csv -Encoding Default -NoTypeInformation -path .\export.csv

出力結果

f:id:shinmai_papa:20210310232742p:plain

Excelで開くとわかりませんが、デフォルトだと、ダブルクォーテーションで囲まれて出力されます。

f:id:shinmai_papa:20210310232738p:plain

このようにPsObjectであれば簡単にCSV形式に変更することができます。

そしてJSONへ

また、CSVだけではなく、JSON等にも変換することもできます。

PS C:\Users\USER\Desktop> $data|ConvertTo-json
[
    {
        "生年月日":  "19881203",
        "名前":  "山田太郎      ",
        "出身地":  "東京都千代田区丸の内                    "
    },
    {
        "生年月日":  "19740212",
        "名前":  "城之内次郎     ",
        "出身地":  "千葉県千葉市花見川区                    "
    },
    {
        "生年月日":  "19620924",
        "名前":  "範馬勇次郎     ",
        "出身地":  "栃木県宇都宮市鶴田町                    "
    }
]

さらにxmlへ・・・

ConvertTo-Xmlコマンドレットでxmlへ変換も簡単です。

PS C:\> ($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に変換してしまえば、後は煮るなり焼くなり簡単に料理することができる

ということがおわかりいただけた(?)かと思います

これを使いこなせればもう固定長なんてこわくない!!

・・・かも知れません。

でも固定長みたいに汎用機系でよく出てくるワードに「文字コード」という壁もあったりなんだりで

同時にぶち当たることもありますね。

なのでこのスクリプトだけで問題を解決できるかどうかは、わかりません。

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

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

PowerShellに関する他の記事

www.tekizai.net

www.tekizai.net

www.tekizai.net