2007年4月25日水曜日

PHP-5.2.1で、文字列をCSVとして分割したかったんだけど・・・

(以下は、今日現在の話なので、将来は状況が変化していると思われます)



PHPのversion 5.2.1を使って、ちょっとしたプログラムを書いていたとき、文字列をCSVとみなして、カンマ(,)区切りで分割する処理が必要になりました。



とりあえず!ってことで、はじめのうちは、preg_split('/,/',・・・)で分割していたのですが、やっぱりどうしても、カンマを含むフィールドがでてきて、「a,b,"cde,fg",e」のような、ダブルクォートなどを使った、カンマのエスケープ処理が必要になってきました。



というわけで、PHPのマニュアルを見ると、

fgetcsv  ファイルポインタから行を取得し、CSVフィールドを処理する



http://www.php.net/manual/ja/function.fgetcsv.php


という、CSVファイルから読み出すときに分割してくれる関数はあるのですが、文字列に対して処理する関数は見当たりません。



ひょっとして、文字列をfopenするような関数もあるかな?と思ったけど、それも見当たりません。



まじかよ~なんだよ~・・・ってことで、FreeBSD使いなので、当然ports使いでもあるわけなので、いきなり「cd /usr/ports/lang/php5; make patch」 とかやって、PHP-5.2.1のソースコードを展開し、grep -Rとかで探しちゃうわけです。これだからFreeBSDはやめられません(笑)。



で、ソースコードをさらっと眺めてみたのですが、やっぱり、fgetcsvの処理の途中、フィールドに分ける処理が組み込まれちゃっているようで、文字列をCSVとして分割する関数は、見当たらないようです。





ところが、ちょこっとgoogleで検索してみたりすると

str_getcsv  CSV 文字列をパースして配列に格納する



http://jp.php.net/manual/ja/function.str-getcsv.php

なんて関数がでてくるじゃありませんか。



でも、php-5.2.1じゃ使えませんでした。なんだよ、このマニュアルは~。期待もたせやがってっ! ぷんぷん。



「might be only in CVS」とか書いてあるので、リリース前のバージョンのphpでのみ使えるってことでしょうか。



☆ ☆ ☆ 



で、結局どうやったかというと、

「,」を含むフィールドは、「,」を「;」に置換しておく

という、非常にその場しのぎな対策をして、お茶を濁すことにしました。

php-5.2.2とかになったら、str_getcsvが使えるようになっているだろう
きっと、そうに違いない!!

という望みをもって。





なんか、ここに、それっぽいコードが書いてありますけどね・・・



http://www.php.net/manual/en/function.split.php



3 件のコメント:

  1. EteranalHarvest2008年2月14日 10:25

    正規表現で次のようにして
    preg_match_all('/"([^"]*)"(?=[\s,]+)[\s,]+/', $buf, $col);
    $matches[1][n] のように参照すればCSVをテキストから読めると思います。ちなみ「"」からカンマの直前の「"」で囲まれた文字列にマッチします。ただ、間に「"」を含んではいけませんがそれは当たり前だと思うので例外処理をしませんでしたがバグの原因になるかも。「"」で囲まれていなければマッチしない仕様ですが、「|」をつかって分岐してやれば対応してやれないこともないかと。もちろん、間にいくつカンマがあっても問題ないです。

    返信削除
  2. EteranalHarvest2008年2月15日 0:17

    preg_match_all の第3引数が$colになっていますが、$matches の間違いでした。すみません。

    返信削除
  3. どうもありがとうございます。解読してみます。
    "~"の中で、"を「\"」でエスケープしたいとか、だんだんと欲が出てきてしまいそうなので、KISSの法則(よけいな機能を作りこまずに、単純にしておけ)で逃げるかもしれません・・・。

    返信削除