dポイントプレゼントキャンペーン実施中!

 都合のいい質問だと分かってて質問しています。

 今、データの読み込みプログラムを作っています。
 件数は12万件(11MB)です。

・データはCSV形式になっており、区切りはカンマです。
・"" で囲まれたカラムとそうでないカラムがあり、"" で囲まれたカラムの一部には、データとしてカンマが含まれていることがあります。
・また、データにはエスケープシーケンスを含むことが許されており、 \" という文字は囲み記号であると認識してはいけません。

 このようなルールのとき、

   @data = split( /,/, $line );

 というロジックでは分割できませんよね。
 なんで、物凄い複雑なロジックで分割を行う xsplit という独自の関数を作って分割しています。
 ところが、1行ごとにこの xsplit を使用しなければならないため、データが12万件もあると、読み込みだけで15~18秒もかかってしまいます。( split だと3秒で終わります)

 で、少しでもこの時間を縮めるために、上記のルールを崩さずに split の /,/ の部分を変更するだけで分割を行うことはできないもんでしょうか。

 何か思いついた方がいらっしゃいましたら、よろしくお願いします。
(ちなみに拡張モジュール類などの、環境によって動いたり動かなかったりするような物は使えないということでお願いします)

A 回答 (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 を使った方法と同じ結果になりますので、ベンチマークを取って早かった方を使われるとよいでしょう。
    • good
    • 0
この回答へのお礼

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

お礼日時:2004/06/12 11:28

Text::ParseWordsモジュールでできます。


例)
use Text::ParseWords;
@b=quotewords(",",0,"AAA,\"b\",cc");
p join("-",@b);
AAA-b-cc
以上です
    • good
    • 0
この回答へのお礼

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

お礼日時:2004/06/12 11:27

要するに、



・データはCSV形式になっており、区切りはカンマです。
・"" で囲まれたカラムとそうでないカラムがあり、"" で囲まれたカラムの一部には、データとしてカンマが含まれていることがあります。
・また、データにはエスケープシーケンスを含むことが許されており、 \" という文字は囲み記号であると認識してはいけません。

を処理できる、正規表現があれば良いのですよね。ピッタリのものがあります。

http://www.din.or.jp/~ohzaki/perl.htm#CSV2Values

これを関数化すれば良いと思います。

参考URL:http://www.din.or.jp/~ohzaki/perl.htm#CSV2Values
    • good
    • 0
この回答へのお礼

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

お礼日時:2004/06/12 11:26

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!