Power Query 実務テンプレ | データ取込・更新系:CSVファイルを自動取込(文字コード自動判定)

Excel
スポンサーリンク

まずゴールのイメージをそろえましょう

あなたがやりたいことは、ざっくり言うとこうです。

「フォルダに CSV を置くだけで、Power Query が
いい感じに文字コードを判定して取り込み、
あとは[更新]ボタン一発で毎日使えるようにしたい」

ここでは、そのための「実務テンプレ」を、
プログラミング初心者でも読めるレベルまでかみ砕いて説明します。
途中で出てくる M 言語(Power Query の中身のコード)も、
意味を言葉で解説しながら進めます。


Power Query で CSV を読む基本

CSV 取込の最小パターン

Power Query が CSV を読むときの流れは、とてもシンプルです。

1つだけ覚えておけばOKなキーワードは「Csv.Document」です。
これは「バイナリのデータを、CSVとしてテーブルに変換する関数」です。

最小構成のMコードはこんな感じです。

let
    SourceBinary = File.Contents("C:\Data\incoming\sample.csv"),
    CsvTable = Csv.Document(
        SourceBinary,
        [
            Delimiter = ",",
            Encoding = 65001,
            QuoteStyle = QuoteStyle.Csv
        ]
    )
in
    CsvTable

ここで重要なのは Encoding = 65001 という部分です。
これは「UTF-8 という文字コードで読んでね」という指定です。
もし Shift-JIS なら Encoding = 932 のように書き換えます。

ポイントは、「Excel の通常の開き方」と違って、
Power Query では「どの文字コードで読むか」を明示的に指定できる、ということです。
これが「文字化けを防ぐための一番の武器」になります。

バイナリ → CSV という二段階の意味

File.Contents は「ファイルをそのままバイナリ(ただのデータの塊)として読む」関数です。
Csv.Document は「そのバイナリを、CSVとして解釈してテーブルにする」関数です。

文字コードは「バイナリをテキストに変換するとき」に必要な情報なので、
Csv.DocumentEncoding で指定する、という構造になっています。


「文字コード自動判定」の現実的な考え方

完全自動は難しい、でも「実務的な自動」は作れる

Power Query には「勝手に文字コードを判定してくれる」関数はありません。
ただし、実務では次のような割り切りで十分役に立ちます。

「まず UTF-8 で読んでみて、ダメそうなら Shift-JIS で読み直す」

この「ダメそう」をどう判定するかが肝です。
ここでは、初心者でも理解しやすい「文字化けチェック」の考え方を使います。

例題の前提を決める

説明を分かりやすくするために、次のような CSV を想定します。

  • 1行目はヘッダー(列名)
  • ヘッダーには日本語が含まれている
  • 文字化けすると「�」のような文字が混ざることが多い

この前提を使って、「ヘッダーに変な文字が混ざっていないか」で
文字コードが合っているかどうかを判定します。


実務テンプレ:UTF-8 / Shift-JIS を自動判定して取込む

ステップ1:共通設定(ファイルパスなど)

まずは、ファイルパスや区切り文字を変数にしておきます。
ここは「毎回変わる可能性があるところ」をまとめておくイメージです。

let
    FilePath = "C:\Data\incoming\orders.csv",
    Delim = ","
in
    FilePath

実際のテンプレでは、このあとに UTF-8 と Shift-JIS の両方を試す処理をつなげていきます。

ステップ2:UTF-8 で読み込んでみる

まずは「普通に UTF-8 として読んだらどうなるか」を試します。

let
    FilePath = "C:\Data\incoming\orders.csv",
    Delim = ",",

    SourceBinary = File.Contents(FilePath),

    CsvUtf8 = Csv.Document(
        SourceBinary,
        [
            Delimiter = Delim,
            Encoding = 65001,              // UTF-8
            QuoteStyle = QuoteStyle.Csv
        ]
    ),

    Utf8WithHeader = Table.PromoteHeaders(
        CsvUtf8,
        [PromoteAllScalars = true]
    )
in
    Utf8WithHeader

ここまでで、「UTF-8 前提の普通の CSV 取込」ができています。
次は、この結果が文字化けしていないかをチェックします。

ステップ3:ヘッダーを使った文字化けチェック

考え方はシンプルです。

  1. 列名(ヘッダー)を全部つなげて1つのテキストにする
  2. その中に「�」が含まれていたら、文字化けしているとみなす

Mコードで書くとこうなります。

let
    Utf8WithHeader = ...  // さっきまでの結果がここにある前提

    HeaderNames = Table.ColumnNames(Utf8WithHeader),
    HeaderText = Text.Combine(HeaderNames, ""),
    Utf8HasGarbage = Text.Contains(HeaderText, "�")
in
    Utf8HasGarbage

Utf8HasGarbagetrue なら「UTF-8 では文字化けしている可能性が高い」と判断できます。

ここでの重要ポイントは、「完璧な判定ではないけれど、実務では十分役に立つ」という割り切りです。
ヘッダーに日本語が入っている前提なら、かなり高い確率で判定できます。

ステップ4:Shift-JIS でも読み直して、マシな方を採用する

いよいよテンプレの本体です。
UTF-8 と Shift-JIS の両方で読み、どちらが「まともか」を判定して選びます。

let
    FilePath = "C:\Data\incoming\orders.csv",
    Delim = ",",

    SourceBinary = File.Contents(FilePath),

    // UTF-8 で読み込み
    CsvUtf8 = Csv.Document(
        SourceBinary,
        [
            Delimiter = Delim,
            Encoding = 65001,
            QuoteStyle = QuoteStyle.Csv
        ]
    ),
    Utf8WithHeader = Table.PromoteHeaders(
        CsvUtf8,
        [PromoteAllScalars = true]
    ),
    Utf8HeaderNames = Table.ColumnNames(Utf8WithHeader),
    Utf8HeaderText = Text.Combine(Utf8HeaderNames, ""),
    Utf8HasGarbage = Text.Contains(Utf8HeaderText, "�"),

    // Shift-JIS で読み込み
    CsvSjis = Csv.Document(
        SourceBinary,
        [
            Delimiter = Delim,
            Encoding = 932,
            QuoteStyle = QuoteStyle.Csv
        ]
    ),
    SjisWithHeader = Table.PromoteHeaders(
        CsvSjis,
        [PromoteAllScalars = true]
    ),
    SjisHeaderNames = Table.ColumnNames(SjisWithHeader),
    SjisHeaderText = Text.Combine(SjisHeaderNames, ""),
    SjisHasGarbage = Text.Contains(SjisHeaderText, "�"),

    // 判定ロジック
    ResultTable =
        if Utf8HasGarbage = false then
            Utf8WithHeader
        else if SjisHasGarbage = false then
            SjisWithHeader
        else
            Utf8WithHeader
in
    ResultTable

ここでやっていることを、言葉で整理します。

  1. 同じバイナリから、UTF-8版とShift-JIS版のテーブルを作る
  2. それぞれのヘッダーをチェックして、「�」があるかどうかを見る
  3. UTF-8 が正常なら UTF-8 を採用
  4. UTF-8 がダメで Shift-JIS が正常なら Shift-JIS を採用
  5. 両方ダメなら、とりあえず UTF-8 を返す(最後の保険)

このロジックを「実務テンプレ」として保存しておけば、
あとはファイルパスだけ変えれば、他の CSV にも流用できます。


重要ポイントの深掘り

なぜ「候補を複数試してマシな方を選ぶ」のか

文字コードの自動判定が難しい理由は、
「同じバイト列が、複数の文字コードとしてそれっぽく読めてしまうことがある」からです。

たとえば、英数字だけのファイルなら、UTF-8 でも Shift-JIS でも
ほぼ同じように読めてしまいます。
この場合、「どっちが正しいか」は人間でも判別がつきません。

そこで、実務では次のような割り切りをします。

  • 会社やシステムごとに、だいたい UTF-8 か Shift-JIS のどちらかに絞られている
  • ヘッダーや特定列に日本語が入っていることが多い
  • 文字化けすると「明らかにおかしい文字」が混ざる

この前提を利用して、「候補を2つ試して、マシな方を採用する」という戦略を取るわけです。
完璧ではないけれど、「手作業で毎回インポート設定する」よりは圧倒的に楽になります。

try … otherwise で「落ちないクエリ」にする

もう一段だけレベルを上げると、try … otherwise を使って
「エラーが出ても落ちないクエリ」にできます。

たとえば、何らかの理由で UTF-8 での読み込みがエラーになる場合、
「エラーなら Shift-JIS に切り替える」という書き方ができます。

let
    FilePath = "C:\Data\incoming\orders.csv",
    Delim = ",",
    SourceBinary = File.Contents(FilePath),

    TryUtf8 =
        try
            Csv.Document(
                SourceBinary,
                [
                    Delimiter = Delim,
                    Encoding = 65001,
                    QuoteStyle = QuoteStyle.Csv
                ]
            )
        otherwise
            null,

    ResultTable =
        if TryUtf8 <> null then
            TryUtf8
        else
            Csv.Document(
                SourceBinary,
                [
                    Delimiter = Delim,
                    Encoding = 932,
                    QuoteStyle = QuoteStyle.Csv
                ]
            )
in
    ResultTable

ここでは「文字化け判定」ではなく、「エラーが出たら別のエンコーディングを試す」という発想です。
先ほどの「ヘッダー文字化けチェック」と組み合わせると、かなり堅牢なテンプレになります。


実務での使い方イメージ

毎日 CSV が1ファイル落ちてくるケース

よくあるシナリオを1つイメージしてみましょう。

  • 基幹システムから、毎日 CSV が1ファイル出力される
  • 日によって UTF-8 のときもあれば、Shift-JIS のときもある
  • Excel で開くたびに「テキストファイルウィザード」で設定するのは面倒
  • できれば、フォルダに上書き保存して[更新]ボタンだけで済ませたい

この場合、今日作ったテンプレを Excel の Power Query に仕込んでおけば、
あとは「同じファイル名で上書き → Excel 側で[更新]」という運用にできます。

ファイル名が日付付きで変わる場合は、
「フォルダ内の最新ファイルを1つ選ぶクエリ」と組み合わせることで、
「最新の CSV を自動で拾って、文字コードも自動判定して取り込む」
というところまで持っていくこともできます。


練習とカスタマイズのヒント

練習1:Encoding をわざと間違えてみる

テンプレの Encoding をあえて別の値に変えて、
どんな文字化けが起きるかを体験してみてください。
「文字コードを間違えるとこうなる」が体感できると、
さっきの「文字化けチェック」の意味が一気に腑に落ちます。

練習2:ヘッダーではなく特定列で判定する

もし「ヘッダーは英数字だけで、日本語は中身だけ」という CSV なら、
特定列(たとえば「氏名」列や「商品名」列)を数行分だけ取り出して連結し、
そこに「�」が含まれているかどうかで判定する、という応用もできます。


まとめと次の一歩

ここまでで、

  • Power Query で CSV を読む基本構造
  • Encoding で文字コードを指定できること
  • UTF-8 / Shift-JIS を両方試して「マシな方」を採用するテンプレ
  • 文字化けチェックの考え方
  • try … otherwise によるエラー耐性の強化

まで一通り押さえました。

タイトルとURLをコピーしました