CSVのための正規表現
Posted by mkamo on 2008年7月1日
CSVファイルを読むための正規表現のメモ.
CSVファイルの一行を列に分解するには「"」に囲まれていない「,」で行を分割して,その後各列から余分な「"」を省けばよい.以下でこうした処理を正規表現を使って実現する方法の一例を示す.
まず「"」に囲まれていない「,」で行を分割することを考える.正規表現で表現するために,「"」に囲まれていない「,」,を,後ろに偶数個の「"」が現れる「,」,と読み替える.これを正規表現で書くと,「,(?=(([^"]*"){2})*[^"]*$)」となる.この正規表現で区切って行を分割すればよい.
次に各列から余分な「"」を省くことを考える.余分な「"」を省くには,各列を囲んでいる「"」を削除し,エスケープされた「""」を「"」に戻せばよい.それぞれ「^"|"$」にマッチすれば「」(空文字)に置換,「""」にマッチすれば「"」に置換という処理を行えばよい.
以上をまとめてJavaのコードにしたものを以下に示す.なお,この例では「"」が閉じられていないなど,CSVとして不正な形式の文字列が入力されたときのことは考慮していない.
/** 後ろに偶数個の「"」が現れる「,」にマッチする正規表現. */
private static final Pattern separatingCommaPattern = Pattern.compile(",(?=(([^\"]*\"){2})*[^\"]*$)");
/** 最初と最後の「"」にマッチする正規表現. */
private static final Pattern surroundingDoubleQuatationPattern = Pattern.compile("^\"|\"$");
/** 「""」にマッチする正規表現. */
private static final Pattern escapedDoubleQuoatationPattern = Pattern.compile("\"\"");
/** lineをカンマ区切りで分割して不要な'"'を取り除いたStringの配列を返す. */
public static String[] splitLineWithComma(String line) {
/// '"'で囲まれていない','でlineを分割
String[] cols = separatingCommaPattern.split(line, -1);
String[] ret = new String[cols.length];
for (int i = 0, len = cols.length; i < len; i++) {
String col = cols[i].trim();
/// 最初と最後に'"'があれば削除
Matcher matcher = surroundingDoubleQuatationPattern.matcher(col);
col = matcher.replaceAll("");
/// エスケープされた'"'を戻す
matcher = escapedDoubleQuoatationPattern.matcher(col);
col = matcher.replaceAll("\"");
ret[i] = col;
}
return ret;
}