CSVでカンマセパレータだけを置換する(フィールド内カンマはスルー)
目次
先の記事で、ExcelVBAによるCSVインポートの自作機能を紹介した。その時に端折っていた正規表現によるカンマセパレータの置換を説明する。これが理解できれば、フィールド内の改行コードと行端の改行コードが同じ場合でも対処できる。
また、サクラエディタなどのテキストエディタで、予めCSVデータを今回紹介する正規表現を使って置換しておけば、Excel標準のインポートでもレイアウトを崩さずに取り込めるだろう。
カンマセパレータを置換するための正規表現
それでは本題。カンマのケースを見ていく。次のCSVデータがあるとする。
a,"b,c",d,"e,f,g",h
目標は、カンマセパレータを別文字(ここでは@)に置換することだ。
a@"b,c"@d@"e,f,g"@h
先に結論を示すが、フィールド内カンマを無視して、セパレータとしてのカンマだけにマッチする正規表現が以下だ。
,(?=([^"]*"[^"]*")*(?![^"]*"))
これにマッチしたカンマを別文字に置換すれば良い。
パターンを見出す
このパターンの意図について、説明を試みる。
図の一番上のように、今回扱うCSVデータには、4つのカンマセパレータがある。便宜上、1番目から4番目のカンマセパレータのそれぞれについて、後続の文字列に下線を引いている。
この下線部分にパターンを見いだせる。ダブルクォートがある場合、単独ではなくペアになっていることがわかる。また、フィールド内のカンマの場合は、ダブルクォートのペアを作ろうとすると最後に必ず1個余ることになり、上述のパターンにマッチしない。
さらにこのパターンを正確に表現すれば、次のようになる。
カンマの後続が次のパターンにマッチすれば、そのカンマはセパレータである。
①「"」を含まない文字列 + ②「"」括られた文字列 + ③行末まで「"」を含まない文字列
- ③は、フィールド内カンマをアンマッチにするための条件になる。ダブルクォートが最後に1個余るパターンを除外する。
- ①+②のグループは繰り返し出現しても良い。
そして既に示した正規表現は、このパターンそのものである。
図のオレンジ色が①、緑色が②、紫色が③に相当する。
緑色の両端にダブルクォートが付いていることに留意すること。ダブルクォートのペアだ。
正規表現のおさらい
遅まきながら、この正規表現を理解するためのおさらいをしておく。
正規表現 | 内容 |
---|---|
[^a] | a以外の文字にマッチ |
* | 直前の文字が 0回以上 繰り返す場合にマッチ |
(AB)* | パターンA, パターンBを一つのグループとして、そのグループが 0回以上 繰り返す場合にマッチ |
ptn1(?=ptn2) | 先読み肯定グループ。直後に ptn2 がある ptn1 にマッチ |
ptn1(?!ptn2) | 先読み否定グループ。直後に ptn2 がない ptn1 にマッチ |
先読み肯定グループ、先読み否定グループについては、以下サイトが詳しい。
https://abicky.net/2010/05/30/135112/
正規表現の解析
1番目のセパレータについて、本当にパターンにマッチしているか確認してみる。
オレンジ色と緑色のグループが2回出現していることになる。 正規表現のオレンジ色の最後にアスタリスク「*」が付いているので、オレンジ色がなく緑色の「”b,c”」だけでも、正規表現の黄色のグループとしてマッチする。
また、正規表現の黄色の最後にもアスタリスク「*」が付いているので、グループの繰り返しの出現にマッチする。(「,d,」「"e,f,g"」)は、2回目のグループ出現としてカウントされる。
2~4番目のセパレータについても同様の考え方で、上記の正規表現にマッチすることが分かる。
正規表現の動作チェック
正規表現の動作チェックをWeb上で行える。
例えば、https://regexr.com/ とか、https://weblabo.oscasierra.net/tools/regex/ など。
当記事の正規表現と対象テキストを設定してみた結果が下図。
マッチした部分に自動で色がつくので分かりやすい。
いろいろ試すと勉強になる。
試しにグループの繰り返しを指定する「*」を「{2}」に変えてみた結果が下図。(「{2}」は直前パターンの2回の繰り返しにマッチする)
1番目のセパレータがマッチした。このセパレータの後ろには、ダブルクォートのペアが2個あるのでマッチしたのだ。
次に「{1}」に変えてみた。
2番目と3番目のセパレータがマッチした。このセパレータの後ろには、ダブルクォートのペアが1個だけなのでマッチしたのだ。
最後に「{0}」に変えてみる。
4番目のセパレータがマッチした。このセパレータの後ろには、ダブルクォートのペアが無いのでマッチしたのだ。
正規表現による置換の例
ここまでくれば、あとはセパレータを別文字に置換するだけだ。
先の記事で自作CSVインポート機能のVBAコードを示したが、その中のrepファンクションは、上記の正規表現を使ってカンマセパレータを別文字に置換している。
サクラエディタなら以下のような感じで。
おわりに
今回の正規表現では先読み(look ahead)・後読み(look behind)が使用されているが、sed コマンドではそれが使用できない。
その場合の対応方法は、sed 特有の制御方法があるので、「CSVでカンマセパレータだけを置換する(フィールド内カンマはスルー)・・・SED版」に記す。