がるの健忘録

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

「文字列としてのCSVとかTCVとか」をパースする方法

んとぶっちゃけると「str_getcsv使うな」って感じ。
サンプルとか見てるといかにも「いけそ〜」な感じなのですが。実は「改行」を全く意識してくれないので、二次元配列を期待しているのに、ふつ〜に一次元配列でreturnしてくれやがります。

$s = "1,2,3\n4,5,6\n7,8,9\n";
$awk = str_getcsv($s);
var_dump($awk);


っつわけで考えてみました。
結論からいうと「メモリ上に一時ファイル作ってからfgetcsv」がよろしげな感じ。
…っつか、str_getcsv、同じ挙動しろよ orz


php://memory および php://temp」については、マニュアルを参照。
php.net/manual/ja/wrappers.php.php

php://memory および php://temp は読み書き可能なストリームで、一時データをファイルのように保存できるラッパーです。 両者の唯一の違いは、 php://memory が常にデータをメモリに格納するのに対して php://temp は定義済みの上限 (デフォルトは 2 MB) に達するとテンポラリファイルを使うという点です。 このテンポラリファイルの場所は、 sys_get_temp_dir() 関数と同じ方法で決めます。
php://temp のメモリ制限を制御するには /maxmemory:NN を追加します。この NN はメモリに保持するデータの最大量で、単位はバイトです。 このサイズを超えるとテンポラリファイルを使います。

微妙ではあるんだけど、一応外に向けるところに作るので、万が一を考えてphp://tempを利用。多分、/maxmemoryも指定したほうがいいんだろうなぁとか思いつつ、そこはサンプルなので、雑w


まず実験一発目。

$s = "1,2,3\n4,5,6\n7,8,9\n";
$fp = fopen('php://temp', 'r+');
fwrite($fp, $s);
fseek($fp, 0, SEEK_SET);

while($row = fgetcsv($fp)) {
  var_dump($row);
}

いけるぽい。


念のために、"によるエスケープを確認。

$s = "1,2,3\n4,\"5\",6\n7,8,9\n";
$fp = fopen('php://temp', 'r+');
fwrite($fp, $s);
fseek($fp, 0, SEEK_SET);

while($row = fgetcsv($fp)) {
  var_dump($row);
}

ぐっど。


次「CSVで、データとしてカンマとか改行とか」にチャレンジ。

$s = "1,2,3\n4,\"5,5.5\n5.6\",6\n7,8,9\n";
$fp = fopen('php://temp', 'r+');
fwrite($fp, $s);
fseek($fp, 0, SEEK_SET);

while($row = fgetcsv($fp)) {
  var_dump($row);
}

無問題。


ある意味眼目「TSV」を確認。

$s = "1\t2\t3\n4\t5\t6\n";
$fp = fopen('php://temp', 'r+');
fwrite($fp, $s);
fseek($fp, 0, SEEK_SET);

while($row = fgetcsv($fp, 0, "\t")) {
  var_dump($row);
}

いけてる。


「長さバランバラン」で「データとしてタブと改行」入り。

$s = "a\tb\t\"aa\tbb\ncc\"\nb\tb\tb\tb\tb\nc\tc";
$fp = fopen('php://temp', 'r+');
fwrite($fp, $s);
fseek($fp, 0, SEEK_SET);

while($row = fgetcsv($fp, 0, "\t")) {
  var_dump($row);
}

おk。


ちなみにやっぱり面倒だからfcloseとかしてませんが、メモリ圧迫するから実務ではとっととcloseしておきませう。
ftruncateはどうなんだろう…念のために消しておきたい気もするけど、蛇足な気もする。


…こーやって、いらんTipsがまた一つ溜まっていく orz


追伸
文字コード、気をつけてね。
mb_language「ぢゃなくて」setlocaleで設定、だから。
http://d.hatena.ne.jp/gallu/20120726/p1