• ベストアンサー

データ分割 正規表現だけで可能?

 都合のいい質問だと分かってて質問しています。  今、データの読み込みプログラムを作っています。  件数は12万件(11MB)です。 ・データはCSV形式になっており、区切りはカンマです。 ・"" で囲まれたカラムとそうでないカラムがあり、"" で囲まれたカラムの一部には、データとしてカンマが含まれていることがあります。 ・また、データにはエスケープシーケンスを含むことが許されており、 \" という文字は囲み記号であると認識してはいけません。  このようなルールのとき、    @data = split( /,/, $line );  というロジックでは分割できませんよね。  なんで、物凄い複雑なロジックで分割を行う xsplit という独自の関数を作って分割しています。  ところが、1行ごとにこの xsplit を使用しなければならないため、データが12万件もあると、読み込みだけで15~18秒もかかってしまいます。( split だと3秒で終わります)  で、少しでもこの時間を縮めるために、上記のルールを崩さずに split の /,/ の部分を変更するだけで分割を行うことはできないもんでしょうか。  何か思いついた方がいらっしゃいましたら、よろしくお願いします。 (ちなみに拡張モジュール類などの、環境によって動いたり動かなかったりするような物は使えないということでお願いします)

質問者が選んだベストアンサー

  • ベストアンサー
  • leaz024
  • ベストアンサー率75% (398/526)
回答No.3

No.1 で紹介されたページのアルゴリズムは、エスケープシーケンスに対応していません。 これを対応させると以下のようになります。(ちょっと簡素化してます。)   chomp $line;   # 改行が既に削除されていれば不要です。   @data = "$line," =~ /("[^"]*(?:\\"[^"]*)*"|[^,]*),/g; $line の値が   ABC,"foo,bar","hoge=\"baz,123\"",\"ok?,:-)\" だとすると、@data の要素は   ABC   "foo,bar"   "hoge=\"baz,123\""   \"ok?   :-)\" となります。 また、要素に含まれる囲みクォートを削除し、\" を " に戻すには、   @data = map { s/^"(.*)"$/$1/; s/\\"/"/g; $_ }     "$line," =~ /("[^"]*(?:\\"[^"]*)*"|[^,]*),/g; とします。すると @data の要素は   ABC   foo,bar   hoge="baz,123"   "ok?   :-)" となります。 こちらの方法は、No.2 で紹介された Text::ParseWords を使った方法と同じ結果になりますので、ベンチマークを取って早かった方を使われるとよいでしょう。

noname#25358
質問者

お礼

 ありがとうございます。  色々試してみて一番いい方法を探してみようと思います。

その他の回答 (2)

回答No.2

Text::ParseWordsモジュールでできます。 例) use Text::ParseWords; @b=quotewords(",",0,"AAA,\"b\",cc"); p join("-",@b); AAA-b-cc 以上です

noname#25358
質問者

お礼

 ありがとうございます!  やってみますね。

  • Dpop
  • ベストアンサー率51% (279/544)
回答No.1

要するに、 ・データはCSV形式になっており、区切りはカンマです。 ・"" で囲まれたカラムとそうでないカラムがあり、"" で囲まれたカラムの一部には、データとしてカンマが含まれていることがあります。 ・また、データにはエスケープシーケンスを含むことが許されており、 \" という文字は囲み記号であると認識してはいけません。 を処理できる、正規表現があれば良いのですよね。ピッタリのものがあります。 http://www.din.or.jp/~ohzaki/perl.htm#CSV2Values これを関数化すれば良いと思います。

参考URL:
http://www.din.or.jp/~ohzaki/perl.htm#CSV2Values
noname#25358
質問者

お礼

 ありがとうございます(^^)  見てみますね!