• ベストアンサー

perl 特定の文字列をdatファイルから抽出したいです。

ホームページ上の日記を作成中です。 わからないことがあったのでお助けください。 たとえば、nikki.cgiファイルの中に、 20030426Sat という文字列が格納されている変数$valueが 存在したとします。 その変数$valueの値を使用して、CGIファイルは、 nikki.datの中から、その 20030426Satが含まれている一行を探し出そうとするという作りにしたいと思っています。 nikki.datの構成は、 一日ごとのコンテンツを改行コードで区切ることにします。 一行分の内容は、 例えば、 20030426Sat,17:32,今日はいい天気だった というように、日付、時間、日記本文というようにしたいと思っています。 長くなりましたが、この日付の文字列をnikki.datファイルの中から見つけ出して、その一行分を抽出するには、どのような関数を使えばよいのでしょうか? また、nikki.datファイルに日記を書き込む処理を別途させなくてはならないので、ちょっと私の考えは非効率かと思っていたりします。 日記作製の際のCGIの効率的な利用方法をご存知でしたら教えてください。 一応カレンダーは完成しています。カレンダーをクリックするとその日の日記が表示されるという仕組みです。 アドバイスをお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • ikspiari
  • ベストアンサー率48% (29/60)
回答No.3

whileを抜けた段階で@datasに該当行が配列として格納されていますよ。 くっつけたいならjoinを使いましょう。 closeした後で、 $line = join(",",@datas); とか。 ソースを省略したのですが、このままのソースですと$valueと一致する行がない場合に最後の行が@datasに代入されてしまいますので注意してください。 一致した時に、 $match = true; とかして、後で$matchのチェックをするといいですね。 参考になりましたら幸いです。

shevy
質問者

お礼

ありがとうございます。 もう二点尋ねさせてください。 配列に関してですが、whileの中に入っている@dates配列はループするごとに上書きされていると 考えて宜しいでしょうか? $match=true というのはif文の中で使うと思うのですが、 どのように使えばいいのでしょう? $valueと一致する行がない場合、 「その日の日記はありません」 というデータを表示したいので、errorを送り返すようにしたいと思っています。 if( $datas[0] eq $value){ $match=true; last; } と、上記のような具合であとは、 $matchがfalseの場合は、errorメッセージを別途作成すればよいかなと思っています。

その他の回答 (4)

  • ikspiari
  • ベストアンサー率48% (29/60)
回答No.5

@dates配列はループするごとに上書きされます。 処理の考え方も問題ないと思います。 &error('その日の日記はありません') if ( $match eq false ); みたいな感じでしょうか。 エラー処理はサブルーチンにしておくと何かと楽ですよ。 ファイルの内容を一度に配列に読み込む方法をよく見かけますが、メモリの効率が悪いのであまりお勧めできません。 それと、頭の中で考えてるよりも実行結果をご自身で体験した方がいいと思いますよ。

shevy
質問者

お礼

ありがとうございます。 ご指摘のとおり、色々と試しながら実行していこうと思います。一応実行しているのですが、まだすくリプティングに振り回されることが多く、頭が混乱しがちです。 今回の質問もじっくり勉強した上で考察させていただきますね。 ありがとうございました!

  • ShaneOMac
  • ベストアンサー率39% (356/898)
回答No.4

方法は一つではないと思いますが、私の場合は、ファイル処理を伴うなら、 1.ファイルオープン 2.読込・データ格納 3.ファイルクローズ 4.データ処理 ときちんと段階で分ける方を好みます。加工を行うならその後に、 5.ファイルオープン 6.書き込み 7.ファイルクローズ この方がすっきりして何をその段階でやっているのか見やすいので良いかと思いますが、自分で分かるというなら形式はどちらでも良いです。 open(FL,"<nikki.dat"); @data=<FL>; close(FL); $i=0; while(@data[$i]){  $datahash{"@data[$i]"}="@data[$i+1]";  $i+=2; } @keylist=keys %datahash; 一行おきに日付・記述というデータ構成ならこういう具合に連想配列に納めてキーリスト(日付)が取れます。日付検索を行いたいならキーリストに対してindex関数や比較(eq)処理をかけて調査します。

shevy
質問者

お礼

ありがとうございます。 参考スクリプト、じっくり読ませていただきました。 ファイル処理というのは、なかなか骨のあるというか、まだperl入門者の私には手ごたえのあるスクリプティングですね。でもその分、やりがいを感じます! ご説明の連想配列の仕組みをじっくりと 呼んで、スクリプティングに生かそうと思います。 ご丁寧にありがとうございました!

  • ikspiari
  • ベストアンサー率48% (29/60)
回答No.2

splitを使いましょう。 $logfile="nikki.dat"; open(IN,"$logfile"); while(<in>){ chomp; @datas = split(","); last if( $datas[0] eq $value ); } close(IN); こんな感じでしょうか? カンマで区切った要素を@datasという配列に代入しています。 @datasの配列の最初の値と$valueを比較しています。 動作未確認ですが。

shevy
質問者

お礼

ありがとうございます。 なるほど!splitを使うんですね。 ところが、この$date[0]と$valueがイコールになったときに、 該当した一行分のデータを取り出して変数に格納したいのですが、 if文のあとにどのように書けば宜しいでしょうか。 教えてくださったスクリプトだと、 該当箇所のところが見つかった段階で、そのループを抜け出してしまっているだけになり、 日記データの格納作業が抜けてしまっている?ように思います。 よろしくお願いします。

  • ShaneOMac
  • ベストアンサー率39% (356/898)
回答No.1

いずれにせよファイルを開いて読み出し中身を変数に入れなければなりませんね。普通は行毎の配列変数に取り込んで処理します。 この場合はその変数に対してindex関数をループで当てていき、中身に調べたい文字列がないかチェックしていけば良いでしょう。 ただしこのようなデータベース型のファイル管理をする場合には連想配列を使った方が効率が良いと思います。<日付-改行-データ-改行>という構成にして日付を独立したラベルに持つ変数としてデータを取りだし、日付をindex関数でチェックしていきます。

shevy
質問者

お礼

ありがとうございます。 まず私のとるべき方法というのは、ループ部分だけを以下に記述します。$valueには20030426Satが格納されているとします。 $logfile="nikki.dat"; open(IN,"$logfile"); while(<in>){ if(index($_,$value,)){ {last;} } } と上記のような感じかなと思いましたが、 if文の中が思いつきませんでした。とりあえずindex文で日付が含まれている場所は見つかるかと思いましたが、見つかった時点でlastによりループ脱出といきたいのですが、その前に、見つかった行の文字列をすべて変数に格納する必要がありますが、それがわかりません。 データベース方のファイル管理の効率性についてですが、私も自分の方法は効率が悪いと思っています。 例えば連想配列%nikkiというのを作製して、 $nikki{$date}と書くことで、 $dairy を取り出すということですよね? ($dateが日付で、$dairyがデータという意味です) 連想配列の意味は、このサイトで何度もお世話になったおかげで理解しているつもりですが、 今回の日記の日付とデータに関しての 管理における連想配列の用い方がもう一つ、 わからないので、もう少し詳しく教えていただけないでしょうか。 長くなってしまいましたが、どうぞよろしくお願いします。

専門家に質問してみよう