LoginSignup
3
7

More than 5 years have passed since last update.

Excel から出力された汚い CSV を読み込むための定型文

Last updated at Posted at 2018-04-20

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

3
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7