php の質問です。以下は 20091020 のような日付を数値化した名前のフォルダが複数あり、別のリスト(タブ区切りのテキストファイル)と照合して、マッチすると日付に対応した文字列をひろってそれを表示する、という内容のつもりなのですが、一度マッチすると、更新されず、全ての文字列($photo_title の部分)が同じになってしまいます。どこが間違っているのか教えていただけませんでしょうか。


$photo_date_ary = array("20090801","20090915","20091010");
$open = fopen('event_info.dat','r');
for($i = 0; $i < count($photo_date_ary); $i++){
while(($line = fgets($open)) != false){
$event_info = explode("\t",$line);
$event_date = $event_info[0];
if($photo_date_ary[$i] == $event_date){
$photo_title = $event_data[1];
break;
}
}
$line .= $photo_date_ary[$i].'*'.$photo_title.'<br />';
}
print($line);

表示期待例:
20090801*夏祭り
20090915*お月見
20091010*運動会

現状:
20090801*夏祭り
20090915*夏祭り
20091010*夏祭り

event_info.dat 中身
20091010(タブ)運動会(改行)
20090915(タブ)お月見(改行)
20090801(タブ)夏祭り(改行)
(EOF)

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:2009/10/20 06:26:28
  • 終了:2009/10/20 18:38:16

ベストアンサー

id:tdoi No.1

tdoi回答回数174ベストアンサー獲得回数752009/10/20 06:40:16

ポイント100pt

ループの順序がよろしくないです。fgetsのループは1度しか走査していません。

現状で出ている結果のうち、最初のものはマッチしたものですが、その後の2つは、マッチしてbreakで抜けたのではなく、while()の中を一度も通らずに出た後に表示されたものです。

直すのであれば、

for($i = 0; $i < count($photo_date_ary); $i++){
  $open = fopen('event_info.dat','r');
  $found = false;
  while(($line = fgets($open)) != false){
    if($photo_date_ary[$i] == $event_date){
      $photo_title = $event_data[1];
      $found = true;
      break;
    }
  }
  fclose($open);
  if ($found) {
    $line .= $photo_date_ary[$i].'*'.$photo_title.'<br />';
  }
 }

のようにするのが1つです。

何度もファイルオープンするところはこの順序でやるのであれば、工夫して欲しいとこですが。

あるいは逆にループを回して以下のような感じにするかです。

while(($line = fgets($open)) != false){
  $event_info = explode("\t",$line);
  $event_date = $event_info[0];
  for($i = 0; $i < count($photo_date_ary); $i++){
    if($photo_date_ary[$i] == $event_date){
      $photo_title = $event_data[1];
      $line .= $photo_date_ary[$i].'*'.$photo_title.'<br />';
      break;
    }
  }
 }

どちらがいいかはデータ量などによるので、一概には言えませんが。

何かの参考になれば。


http://dummy

id:AKI-NAMI

私の説明が足りなかったようです。

event_info.dat には、例えば、

20090801001(タブ)夏祭り(タブ)コメントA(改行)

20090801002(タブ)夏祭り(タブ)コメントB(改行)

20090801003(タブ)夏祭り(タブ)コメントC(改行)

のように一対一ではありません。

もう少し説明すると、画像ファイル event_img があって、その下に $photo_date_ary の中身のようなナメのフォルダがあり、その 20090801 を タグ付で表示させて、日付に対応したギャラリーを表示させるというものですので、このままでは"見た目"、event_info.dat の内容を表示しただけになってしまいます。

while 以下の部分が一度しか通っていないことはわかっていたのですが、なぜ通らないのかが理解できていません。

2009/10/20 17:56:23

その他の回答(2件)

id:tdoi No.1

tdoi回答回数174ベストアンサー獲得回数752009/10/20 06:40:16ここでベストアンサー

ポイント100pt

ループの順序がよろしくないです。fgetsのループは1度しか走査していません。

現状で出ている結果のうち、最初のものはマッチしたものですが、その後の2つは、マッチしてbreakで抜けたのではなく、while()の中を一度も通らずに出た後に表示されたものです。

直すのであれば、

for($i = 0; $i < count($photo_date_ary); $i++){
  $open = fopen('event_info.dat','r');
  $found = false;
  while(($line = fgets($open)) != false){
    if($photo_date_ary[$i] == $event_date){
      $photo_title = $event_data[1];
      $found = true;
      break;
    }
  }
  fclose($open);
  if ($found) {
    $line .= $photo_date_ary[$i].'*'.$photo_title.'<br />';
  }
 }

のようにするのが1つです。

何度もファイルオープンするところはこの順序でやるのであれば、工夫して欲しいとこですが。

あるいは逆にループを回して以下のような感じにするかです。

while(($line = fgets($open)) != false){
  $event_info = explode("\t",$line);
  $event_date = $event_info[0];
  for($i = 0; $i < count($photo_date_ary); $i++){
    if($photo_date_ary[$i] == $event_date){
      $photo_title = $event_data[1];
      $line .= $photo_date_ary[$i].'*'.$photo_title.'<br />';
      break;
    }
  }
 }

どちらがいいかはデータ量などによるので、一概には言えませんが。

何かの参考になれば。


http://dummy

id:AKI-NAMI

私の説明が足りなかったようです。

event_info.dat には、例えば、

20090801001(タブ)夏祭り(タブ)コメントA(改行)

20090801002(タブ)夏祭り(タブ)コメントB(改行)

20090801003(タブ)夏祭り(タブ)コメントC(改行)

のように一対一ではありません。

もう少し説明すると、画像ファイル event_img があって、その下に $photo_date_ary の中身のようなナメのフォルダがあり、その 20090801 を タグ付で表示させて、日付に対応したギャラリーを表示させるというものですので、このままでは"見た目"、event_info.dat の内容を表示しただけになってしまいます。

while 以下の部分が一度しか通っていないことはわかっていたのですが、なぜ通らないのかが理解できていません。

2009/10/20 17:56:23
id:taramonera No.2

taramonera回答回数79ベストアンサー獲得回数52009/10/20 10:54:56

ダミー

http://yahoo.co.jp


$photo_title = $event_data[1];

$photo_title = $event_info[1];

ではないでしょうか。

id:AKI-NAMI

質問時の記入ミスです。

「どこが間違っているか」と言えば確かにそうなのですが・・・

2009/10/20 18:00:01
id:kine2525 No.3

きねーま回答回数17ベストアンサー獲得回数02009/10/20 17:08:46

ポイント50pt

http://kine.s333.xrea.com

URLはダミーです(一応自分のサイトではありますが)


既に他の方も回答しているようですが、なおしてみました。


$photo_date_ary= array("20090801","20090915","20091010");

$open = fopen('event_info.dat','r');

$line2="";

while(($line = fgets($open)) != false){

for($i = 0; $i < count($photo_date_ary); $i++){

$event_info = explode("\t",$line);

$event_date = $event_info[0];

if($photo_date_ary[$i] == $event_date){

$photo_title = $event_info[1];

$line2 .= $photo_date_ary[$i].'*'.$photo_title.'
';

break;

}

}

}

print($line2);

?>

ポイントは

・ファイルを読み出すWhile文はFor文の前

ですね。

id:AKI-NAMI

上の方と同じですね。

ファイルを読み出す部分は回す前、と単純に覚えておけばいいでしょうか。

結果は回ったのですが、私の説明不足で回りすぎ?ています。

2009/10/20 18:13:55
  • id:t-wata
    あまりに単純すぎるミスです。
    単に変数をprintして確認するだけですぐに原因がわかると思うけど。
  • id:standard_one
    多分回答は誰が書いても同じだと思うのでそっちは置いといて
    むしろ現状で夏祭りと表示されるのが謎すぎます・・・
  • id:tdoi
    回答の方には書きましたが、夏祭りと表示されるのは、内側のループをbreakではなく、ファイルの終端に達して抜けたときに、最初に格納したデータが残っているというだけの理由だと思いますよ。
  • id:kine2525
    みんな厳しいなぁ・・・プロでもうっかりすると陥りやすいミスだと思うので寛容になりましょうよ。って、本業プログラマでない自分が言えた義理ではないですが。

    >>standard_one
    それは思いました。
    最初の状態のプログラムを打ち込んで期待値にならないのでアレ?って。

    文法もちょっと間違ってた気もしますし、そのままコピペでなく打ち込み直してタイプミスしたんじゃないでしょうか。
  • id:tdoi
    > while 以下の部分が一度しか通っていないことはわかっていたのですが、なぜ通らないのかが理解できていません。

    質問を理解していないのかもしれませんが、ファイルポインタが最初の走査で終端まで来たからではないですか?
  • id:AKI-NAMI
    夏祭りではなく、オール運動会でしたか?
    そのままのコピペではタグや、年月日を分ける部分があったので削ったり、長~い変数名もちょっと恥ずかしかったので短く直しています。

    仕様は細かく読んでもよく理解できていませんし、
    また、こういう質問を通して、リファレンスの説明文に対して「そのように考えるのか」ということがしばしばあるレベルの者です。
  • id:AKI-NAMI
    これも書いてある方がいいのでしょうか。
    opendir,readdir で /event_img/ を調べて、$photo_date_ary で配列を作って、
    新しい順にするために rsort($photo_date_ary,SORT_NUMERIC);
    してあります。
    ので、実際の配列の並びは 20091010, 20090915, 20090801 のようになっています。
  • id:AKI-NAMI
    >tdoi様
    for文に戻るときに勝手に最初を指してくれるのかと漠然と思っていました。

    ということは、使ったことはありませんが、
    rewind($open) を break の直前に書くとかすれば fopen を複数回実行させなくてもいいということなのでしょうか。

    ・・・あ、できました。
    ありがとうございます!!!
  • id:tdoi
    できたようでなによりです。
    rewindを利用することもありですが、データ量などによっては最初に配列に格納してしまう方が効率が良い場合もありますので、検討してみてください。また、このファイルが大きすぎる場合であれば、配列に格納してしまうとメモリを食いすぎるので、rewindの方がよいかもしれません。
  • id:AKI-NAMI
    >tdoi様
    あらためてありがとうございました。
    2件答えていただいたようなものなので、200pt 差し上げたかったのですが、やり方がわからず、私の通常?のポイントになってしまいました。
    それでも夜間講座と比べたら申し訳ないくらいのお礼ですが・・・

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません