Java

CSVにダブルクォーテーションやカンマが含まれる場合のパース処理 [Java]

この記事では、CSVファイルにダブルクォーテーションやカンマ、改行文字などの、構文を狂わせる要素が含まれる場合のパース方法について紹介しています。

仕事で外部システムと連携する場合など、時として非常に厄介な仕様のCSVファイルを処理しなければならないケースがありますよね?

よくある難しいパターンとしては、

  • CSVのカラム内に改行コードが含まれている
  • CSVのカラム内にカンマが含まれている(金額など)
  • CSVのカラムのダブルクォーテーションの中に更にダブルクォーテーションが含まれている

などでしょう。
この様な仕様のCSVファイルをライブラリ無しで処理する方法について解説します。

この記事で紹介するサンプルコードでは、以下の仕様のCSVファイルを想定しています

  • ファイルの文字コードはShift-JIS
  • 各カラムはダブルクォーテーションで囲われている
  • カラムのダブルクォーテーションが入れ子になっていることがある
  • カラムに改行コードが含まれることがある
  • カラムにカンマが含まれることがある
ゴイチ

ややこしいCSVファイルをスマートに処理する方法を次の章で紹介します。

サンプルコード

読み取る具体的なCSVの中身は以下とします。

"1","1,234,567","文字列の途中で
改行コードが
含まれるパターン","文字列に"ダブルクォーテーション"が含まれるパターン"
"2","9,876","改行コードなし","文字列に,カンマ,が含まれるパターン"

サンプルコードを以下に示します。

import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;

public static void parse(String filePath) throws IOException {
    try (BufferedReader br = Files.newBufferedReader(Paths.get(filePath), Charset.forName("SJIS"))) {
        StringBuilder sb = new StringBuilder();

        String line;
        while ((line = br.readLine()) != null) {
            // ファイルから読み取った行を連結する
            sb.append(line);

            if (!StringUtils.endsWith(line, "\"")) {
                // 行末がダブルクォート以外の場合、改行コードが含まれているのでcontinueして次の行へ
                continue;
            }

            // 行の先頭と末尾のダブルクォートを除去した後、"," でsplitする。
            String[] columns = StringUtils.removeStart(
                            StringUtils.removeEnd(sb.toString(), "\""), "\"")
                    .split("\",\"");

            // 結果出力
            System.out.println(StringUtils.join(columns, "|"));

            // StringBuilderの初期化
            sb.setLength(0);
        }
    }
}

出力結果

1|1,234,567|文字列の途中で改行コードが含まれるパターン|文字列に"ダブルクォーテーション"が含まれるパターン
2|9,876|改行コードなし|文字列に,カンマ,が含まれるパターン

解説

ポイントは2つあります。

ココがポイント

  • 行末がダブルクォート以外の場合、改行コードと見なして次の行と連結する
  • 連結した文字列を「","」で split する

改行コードを除去しながら1行分の文字列を作成し、作成した文字列の先頭と末尾の「"」を削除した後、「","」で分割すれば、きれいにパースすることが出来ます。

今回のやり方を応用すれば、改行コードを任意の文字に置き換えたり、カンマやダブルクォーテーションを除去したりすることも出来るはずです。
ぜひ、自身の仕様に合わせてカスタマイズしてみて下さい。

まとめ

最後に、この記事の内容をまとめます。

要点

  • CSVファイルにダブルクォーテーションやカンマ、改行コードが含まれていてもライブラリ無しでパースすることが出来る
  • ポイントは改行文字を除去することと、split に使う文字を工夫すること
  • パース後に変換したい文字があれば、対象文字を replace しても良い

特殊なパターンのCSVファイルの処理方法について解説しました。

この様な難しい処理をする前に、そもそもCSVではなくTSVファイルに仕様を変えて貰うなど、仕様変更で対処することも有効な方法だと思います。
仕様変更で対応することも考慮に入れつつ、どうしてもCSVファイルで処理しなければならない場合などに、今回の例を参考にしてみて下さい。

コーヒーブレイク

今回の様な特殊なケースのコードを考える場合、私の場合、まず頭の中でどういう手順で処理すれば実現できるかを考えます。
この時はプログラミング言語ではなく、日本語で考えています。
日本語で手順を説明できるのであれば、プログラミング言語でも書けるだろうと考えて、それから実装に移っています。

また、CSVファイルで文字コード変換したい場合や、文字化けの検知をしたい場合には以下の記事も参考にしてみて下さい。

CSVファイル UTF-8→SJIS変換 & 文字化け検知 [Java]

この記事では、CSVファイルを読み込み UTF-8からShift-JISに文字コードを変換して、別のCSVファイルに出力するサンプルプログラムを紹介します。(BufferedReader / Buff ...

続きを見る

ゴイチ

それでは、また他の記事でお会いしましょう!

この記事は役に立ちましたか?

  • この記事を書いた人
アバター画像

ゴイチ

ソフトウェアエンジニア歴20年。 C/C++、Java、C#、Kotlinが得意で、組込系からAndroidアプリ、大規模なWebサービスなど幅広いプログラミング経験があります。 現在は某SNSの会社でWebエンジニアをしています。

-Java
-, ,