LoginSignup
13
5

More than 3 years have passed since last update.

ruby 2.7.0 CSV の liberal_parsing オプションについて調査してみた

Posted at

概要

Ruby標準ライブラリのCSVの挙動についてのまとめ。
ruby 2.4.0 CSV の liberal_parsing オプションについて調査してみた のruby2.7.0バージョン。

csvの仕様

rubyの標準ライブラリのCSVパーサーではRFC4180準拠のパースが行われる。
こちらの仕様では、コンマの直後と次のコンマの直前に"をおくことで、コンマを含んだ文字列を一つのフィールドとして扱うことができる。

CSV.parse('a,"b,c",d')
=> [["a", "b,c", "d"]]

ダブルクオートを含む文字列を表すためには、もう一つのダブルクオートでエスケープする必要がある。

CSV.parse('a,"b""c",d')
=> [["a", "b\"c", "d"]]

しかし、RFC4180はなかなか厳密な仕様で例えば a,b"c,d のような文字列は不正なcsvになり、例外が発生する。

CSV.parse('a,b"c,d')      # CSV::MalformedCSVError (Illegal quoting in line 1.)

一方で上記のようなフォーマットは頻繁に出てきうるため、これを厳密にエラーにしていると取り扱いが難しい場合がある。そのために実用的なパースを行うためのliberal_parsingというオプションがruby2.4.0から導入されている。
上記の記事ではruby2.4を使ってliberal_parsingの挙動について調査を行っているが、ruby2.7で確認したところ挙動が変わっていたところも多くあったのでここでまとめておく。全般的にruby2.7の方が挙動が直感的になっている。

liberal_parsing のruby2.7での挙動

ダブルクォートに囲まれたフィールドの場合

正しくエスケープされたダブルクォートの場合

CSV.parse('a,"bb""b",c', liberal_parsing: true)
=> [["a", "bb\"b", "c"]]

文中にエスケープされていないダブルクォートがある場合

CSV.parse('a,"bb"b",c', liberal_parsing: true)
=> [["a", "\"bb\"b\"", "c"]]

ruby2.4では例外は発生していた。

ダブルクォートに囲まれていないフィールドの場合

途中にダブルクォートがある場合

SV.parse('a,bb"b,c', liberal_parsing: true)
=> [["a", "bb\"b", "c"]]

途中にエスケープされたダブルクォートがある場合

CSV.parse('a,bb""b,c', liberal_parsing: true)
=> [["a", "bb\"\"b", "c"]]

先頭にのみダブルクォートがある場合

CSV.parse('a,"bbb,c', liberal_parsing: true)
# CSV::MalformedCSVError (Unclosed quoted field in line 1.)

ruby2.4と同様に例外。

先頭と途中にダブルクォートがあって、ダブルクォートの合計が偶数の場合

CSV.parse('a,"bb"b,c', liberal_parsing: true)
=> [["a", "\"bb\"b", "c"]]

先頭と途中にダブルクォートがあって、ダブルクォートの合計が奇数の場合

CSV.parse('a,"b"b"b,c', liberal_parsing: true)
=> [["a", "\"b\"b\"b", "c"]]

ruby2.4では例外が発生していたが、ruby2.7ではパースできるようになった。

末尾と途中にダブルクォートがある場合

CSV.parse('a,bb"b",c', liberal_parsing: true)
=> [["a", "bb\"b\"", "c"]]

ruby2.4と同様にパースできる。

13
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5