Excel などからエクスポートした CSV は非常識なフォーマットであることが多く、Import-CSV を以ってしても読み込みに失敗することが少なくない。
そのような場合に、CSV 表のレイアウトが変更されていないかチェックしつつ、上手く読み込む方法をメモしておく。
$organized_csv_data = cat .\chaotically_separated_values.csv |
ForEach-Object -begin {
$i = 0
} -process {
$i += 1
# ヘッダのバリデーション
if ($i -eq 1) { if ($_ -eq '$i 行目に想定される値') { return } else { throw "$i 行目が変更されています" } }
# ... 必要なだけバリデーション行の繰り返し
# 本来こうであって欲しいという CSV ヘッダ
if ($i -eq $EndOfHeaderLines) {'問題なかった場合に生成するヘッダ'}
# データ部分はそのままパイプに流す
$_
} |
Out-String |
ConvertFrom-CSV
cat
で csv を読み込むと文字列の配列になり ConvertFrom-CSV
では上手く処理できないことがあるため、Out-String
を挟んでいる。
Excel のまま vba でやったらでええやん、という意見もあると思うが、バッチ的に処理できるメリットは代えがたいものがある。
関数にするとこんな感じになると思う。
Function Test-CSV {
param(
[scriptblock]$Expects,
[scriptblock]$Headers
)
begin {
$ExpectStrings = & $Expects
$i = 0
$len = $ExpectStrings.length
}
process {
$i += 1
$Actual = $_
if ($i -le $len) {
if ($ExpectStrings[$i-1] -eq $Actual) {
return
} else {
throw "Format Error: line $i `nExpect: $($ExpectStrings[$i]) `nActual: $Actual"
}
} elseif ($i -eq $len+1) {
& $Headers
$Actual
} else {
$Actual
}
}
}
# 使い方
$csv_data = cat .\chaotically_separated_values.csv |
Test-CSV -Expects {
'一行目に期待する文字列'
'二行目に期待する文字列'
...
} -Headers {
'列名1,列名2,...'
} |
Out-String |
ConvertFrom-CSV