- ベストアンサー
__DATA__の再利用
こんばんは、皆さん。 以下のプログラムは1回しか__DATA__を読み込まないですが、 2回めのprintで__DATA__を表示させるにはどうしたらよいのでしょうか? ------------------------------------------------------ #!/usr/bin/perl $str = "DATA"; $aaa = &test($str); print $aaa; sub test($){ $instr = @_[0]; foreach (<$instr>){ print; } foreach (<$instr>){ print; } } __DATA__ 1 2 3 ------------------------------------------------------
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
DATA は seekable なファイルハンドルなので、tell と seek を使って読み込み位置を変更することができます。 最初のループの前に $fpos_top_of_instr = tell $instr; を入れ、次のループの前に seek $instr, $fpos_top_of_instr, 0; を入れてみて下さい。 # seek $instr, 0, 0; と強制的に先頭に戻すと・・・
その他の回答 (4)
- SE-1
- ベストアンサー率57% (26/45)
> なんで@instrs=<$instr>;でforeach(@instrs)にするとうまく動くんですか? print していただくとわかりますが、 @instrs は (1,2,3) になっていて、foreach(@instrs) の中の print; でそれぞれの要素が表示されます。 コード2は tell の文がコメントアウトされているので、$fpos_top_of_instr が定義されておらず、return の上の seek $instr, $fpos_top_of_instr,0;が seek $instr, 0,0; と同義になっています。それで return <$instr>; しているのでコード全体が戻り値になって @aaa の内容として表示されたのでしょう。 一応、私が意図したところのコードを添付しておきますね。 #!/usr/bin/perl $str = "DATA"; @aaa = &test($str); print "aaa= @aaa\n"; sub test($){ $instr = @_[0]; $fpos_top_of_instr = tell $instr; foreach (<$instr>){ print "data1= $_"; } seek $instr, $fpos_top_of_instr, 0; foreach (<$instr>){ print "data2= $_"; } seek $instr, $fpos_top_of_instr, 0; return <$instr>; } __DATA__ 1 2 3
- SE-1
- ベストアンサー率57% (26/45)
>指定しないと最後に評価した値が返却されたような。 おっしゃられるとおりで、「&test は何も返してない」は間違いだったと思います。すみません。&test で最後に評価されているのは print 文で1が返りそうな気がしますが $aaa は空みたいですね~。↓ >でも1回は表示されました。なぜでしょうかねぇ。 表示されたのはきっと1回目の foreach の中の print の結果ですね。6行目の print $aaa; を print "aaa= $aaa\n"; とすると、そこでは何も表示されていないことが分かります。 2つ目の foreach の下に seek $instr, $fpos_top_of_instr, 0; return <$instr>; を追加して、5-6行目を @aaa = &test($str); print "aaa= '@aaa'\n"; とすると aaa= '1 2 3' と表示されました。 本題とは関係ないことで失礼しました。
お礼
すいません、お礼にしか書けなくなってしまったので、こちらに書きます。 seekをどこに入れたらいいのかわからなかったので、 コード1のようにすると、結果1になりました。 コード2だとaaa=''の「'」の中に、ソースコード全体が入りました。 なぜでしょうか? ---コード1----------------------------------- #!/usr/bin/perl $str = "DATA"; @aaa = &test($str); print "aaa='@aaa'\n"; sub test($){ $instr = @_[0]; #$fpos_top_of_instr = tell $instr; foreach (<$instr>){ print; } #seek $instr, $fpos_top_of_instr, 0; #seek $instr, 0, 0; foreach (<$instr>){ seek $instr, $fpos_top_of_instr,0; return <$instr>; print; } } __DATA__ 1 2 3 ---結果1----------------------------------- 1 2 3 aaa='' ---コード2----------------------------------- #!/usr/bin/perl $str = "DATA"; @aaa = &test($str); print "aaa='@aaa'\n"; sub test($){ $instr = @_[0]; #$fpos_top_of_instr = tell $instr; foreach (<$instr>){ print; } #seek $instr, $fpos_top_of_instr, 0; #seek $instr, 0, 0; foreach (<$instr>){ print; } seek $instr, $fpos_top_of_instr,0; return <$instr>; } __DATA__ 1 2 3
補足
お返事ありがとうございます。 ちょっとなんか変ですよ。 これって関数ですか?サブルーチンですか? なんで@instrs=<$instr>;でforeach(@instrs)にすると うまく動くんですか? 理屈がわかりません。
- leaz024
- ベストアンサー率75% (398/526)
> 詳細が知りたいのですが、その情報はどこに > 掲載されていますでしょうか? tell と seek でファイルの読み込み位置を制御するというのはファイル操作の基礎知識みたいなものなので、どこにでも載っていると思います。 ただ、DATA を再読み込みすることを念頭に探すと、そもそもそんなことをする人はあまりいないでしょうから、途端に見つけるのが難しくなります。 DATA はファイルハンドルですから、seek さえ知っていれば「DATA を seek できないか?」程度のことはすぐに思い付いたでしょうし、ちょっと試してみれば tell が必要なこともすぐに気付いたでしょう。 ファイル操作に限らず、どんな機能の関数があるのか一通り知っておかれるとよいと思いますよ。
お礼
貴重な情報をありがとうございます。 tellもseekも知りませんでした。 ということは基礎がまだ身についていないということですね。 初心者の領域を脱してないのは実感していますけど。 DATAを再読み込みするのは一般的じゃないんですね。 確かにデータをソースのファイルに入れるのは、ちょっと考え方が変ですね。 こういう場合は__DATA__を使ってデータを入れるのが良い、という例があるといいんですが。
- SE-1
- ベストアンサー率57% (26/45)
# これじゃだめでしょうか・・ # ちなみに、&test は何も返してないので $aaa は空ですよ。 #!/usr/bin/perl $str = "DATA"; $aaa = &test($str); print $aaa; sub test($){ $instr = @_[0]; @instrs=<$instr>; foreach (@instrs){ print; } foreach (@instrs){ print; } } __DATA__ 1 2 3
補足
そうなんですか? これで動かしたら動きましたけど。 returnで明示的に戻り値を指定しないといけないんでしたっけ? 指定しないと最後に評価した値が返却されたような。 それでも、表示されないはずですね。 でも1回は表示されました。 なぜでしょうかねぇ。
補足
お返事ありがとうございます。 詳細が知りたいのですが、その情報はどこに 掲載されていますでしょうか? Webでは見つかりませんでした。 よろしくお願いします。