この記事では、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ファイルで処理しなければならない場合に、今回の例を参考にしてみて下さい。
また、今回紹介したパターンでは上手く行かなかったケースがあれば、ぜひコメント欄で教えて頂けるとありがたいです。
最後まで読んでいただきありがとうございました。