- ベストアンサー
データ分割 正規表現だけで可能?
都合のいい質問だと分かってて質問しています。 今、データの読み込みプログラムを作っています。 件数は12万件(11MB)です。 ・データはCSV形式になっており、区切りはカンマです。 ・"" で囲まれたカラムとそうでないカラムがあり、"" で囲まれたカラムの一部には、データとしてカンマが含まれていることがあります。 ・また、データにはエスケープシーケンスを含むことが許されており、 \" という文字は囲み記号であると認識してはいけません。 このようなルールのとき、 @data = split( /,/, $line ); というロジックでは分割できませんよね。 なんで、物凄い複雑なロジックで分割を行う xsplit という独自の関数を作って分割しています。 ところが、1行ごとにこの xsplit を使用しなければならないため、データが12万件もあると、読み込みだけで15~18秒もかかってしまいます。( split だと3秒で終わります) で、少しでもこの時間を縮めるために、上記のルールを崩さずに split の /,/ の部分を変更するだけで分割を行うことはできないもんでしょうか。 何か思いついた方がいらっしゃいましたら、よろしくお願いします。 (ちなみに拡張モジュール類などの、環境によって動いたり動かなかったりするような物は使えないということでお願いします)
- みんなの回答 (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 を使った方法と同じ結果になりますので、ベンチマークを取って早かった方を使われるとよいでしょう。
その他の回答 (2)
- mosuradazo
- ベストアンサー率60% (6/10)
Text::ParseWordsモジュールでできます。 例) use Text::ParseWords; @b=quotewords(",",0,"AAA,\"b\",cc"); p join("-",@b); AAA-b-cc 以上です
お礼
ありがとうございます! やってみますね。
- Dpop
- ベストアンサー率51% (279/544)
要するに、 ・データはCSV形式になっており、区切りはカンマです。 ・"" で囲まれたカラムとそうでないカラムがあり、"" で囲まれたカラムの一部には、データとしてカンマが含まれていることがあります。 ・また、データにはエスケープシーケンスを含むことが許されており、 \" という文字は囲み記号であると認識してはいけません。 を処理できる、正規表現があれば良いのですよね。ピッタリのものがあります。 http://www.din.or.jp/~ohzaki/perl.htm#CSV2Values これを関数化すれば良いと思います。
お礼
ありがとうございます(^^) 見てみますね!
お礼
ありがとうございます。 色々試してみて一番いい方法を探してみようと思います。