• ベストアンサー

__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 ------------------------------------------------------

noname#17299
noname#17299
  • Perl
  • 回答数5
  • ありがとう数2

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

  • ベストアンサー
  • leaz024
  • ベストアンサー率75% (398/526)
回答No.2

DATA は seekable なファイルハンドルなので、tell と seek を使って読み込み位置を変更することができます。 最初のループの前に $fpos_top_of_instr = tell $instr; を入れ、次のループの前に seek $instr, $fpos_top_of_instr, 0; を入れてみて下さい。 # seek $instr, 0, 0; と強制的に先頭に戻すと・・・

noname#17299
質問者

補足

お返事ありがとうございます。 詳細が知りたいのですが、その情報はどこに 掲載されていますでしょうか? Webでは見つかりませんでした。 よろしくお願いします。

その他の回答 (4)

  • SE-1
  • ベストアンサー率57% (26/45)
回答No.5

> なんで@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)
回答No.4

>指定しないと最後に評価した値が返却されたような。 おっしゃられるとおりで、「&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' と表示されました。 本題とは関係ないことで失礼しました。

noname#17299
質問者

お礼

すいません、お礼にしか書けなくなってしまったので、こちらに書きます。 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

noname#17299
質問者

補足

お返事ありがとうございます。 ちょっとなんか変ですよ。 これって関数ですか?サブルーチンですか? なんで@instrs=<$instr>;でforeach(@instrs)にすると うまく動くんですか? 理屈がわかりません。

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.3

> 詳細が知りたいのですが、その情報はどこに > 掲載されていますでしょうか? tell と seek でファイルの読み込み位置を制御するというのはファイル操作の基礎知識みたいなものなので、どこにでも載っていると思います。 ただ、DATA を再読み込みすることを念頭に探すと、そもそもそんなことをする人はあまりいないでしょうから、途端に見つけるのが難しくなります。 DATA はファイルハンドルですから、seek さえ知っていれば「DATA を seek できないか?」程度のことはすぐに思い付いたでしょうし、ちょっと試してみれば tell が必要なこともすぐに気付いたでしょう。 ファイル操作に限らず、どんな機能の関数があるのか一通り知っておかれるとよいと思いますよ。

noname#17299
質問者

お礼

貴重な情報をありがとうございます。 tellもseekも知りませんでした。 ということは基礎がまだ身についていないということですね。 初心者の領域を脱してないのは実感していますけど。 DATAを再読み込みするのは一般的じゃないんですね。 確かにデータをソースのファイルに入れるのは、ちょっと考え方が変ですね。 こういう場合は__DATA__を使ってデータを入れるのが良い、という例があるといいんですが。

  • SE-1
  • ベストアンサー率57% (26/45)
回答No.1

# これじゃだめでしょうか・・ # ちなみに、&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

noname#17299
質問者

補足

そうなんですか? これで動かしたら動きましたけど。 returnで明示的に戻り値を指定しないといけないんでしたっけ? 指定しないと最後に評価した値が返却されたような。 それでも、表示されないはずですね。 でも1回は表示されました。 なぜでしょうかねぇ。

関連するQ&A

  • メインルーチンの変数をモジュールに渡す

    Perlの勉強をし始めの者なんで、恥ずかしい質問ですけど・・・ モジュールの使い方です。 以下のプログラムではTest_module.pmで定義した変数$testをメインルーチンでprintしています。 ***** メインルーチン *****  #perl /usr/bin/perl  use Test_module;  our $test=10;  print $Test_module::test; ***** Test_module.pm *****  package Test_module;  our $test=10;  1; これはちゃんと動いています。 ところが逆にメインルーチンで定義した変数$testをTest_module.pmに渡そうとすると、うまくいきません。 以下のプログラムをどう直せばいいのでしょうか。 ***** メインルーチン *****  #perl /usr/bin/perl  use Test_module;  our $test=10;  &Test_module::print_test(); ***** Test_module.pm *****  package Test_module;  sub print_test {  print $Main::test;  }  1;

    • ベストアンサー
    • Perl
  • perl 計算結果をファイルへ出力したい

    perl やり始めたばかりです。宜しくお願いします。 入力ファイル data.txt があるとします。 data.txt は、 123 456 789 333 555 777 以上のようなテキストファイルといたします。このファイルを 以下の様に100分の1にして出力したい。 1.23 4.56 7.89 3.33 5.55 7.77 と言うことで、この場で教えていただきました。それが、以下です。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); foreach $line (@x){ chomp($line); @elms = split(' ',$line); foreach $data (@elms){ print $data/100," "; } print "\n"; } おかげ様でこれはこれで上手く動きました。そこで、出力値をファイルに 書き込みたいのです。 もちろん、以下の様な方法でファイルに 書き込めるのは判っております。 計算プログラム.pl > outfile.txt しかし、上のプログラムをベースにファイルに書き込めないかと色々と 試してはみましたが、どうも上手く行きません。 どなたか教えて頂けないでしょうか? 宜しくお願い申し上げます。

    • ベストアンサー
    • Perl
  • HTMLからCGIへデータを引き継ぎ

    HTMLでメールフォームを作りCGI(Perl)で次のプログラムを作りました。 #!/usr/local/bin/perl print "Content-type: text/html\n\n"; print "$mail\n"; print "$namae\n"; print "$naiyou\n"; 動作確認のためプログラムは少しにしました。何も表示されません。

    • ベストアンサー
    • Perl
  • perlでサブルーチンへの複数の配列渡し

    perlでサブルーチンに配列を渡しているのですが、 引数としている配列が1個の場合は問題ないのですが、 複数渡すと、第2引数以降が渡りません。 どの様にすれば上手くできますか。 例1 #!/usr/bin/perl @x1 = (14, 11, 5, 12, 8, 15); @x2 = (12, 10, 8, 9); print "main : @x1 \n"; &test(@x1); sub test { my (@arg1) = @_; print "sub : @arg1 \n"; } 結果 main : 14 11 5 12 8 15 sub : 14 11 5 12 8 15 例2 #!/usr/bin/perl @x1 = (14, 11, 5, 12, 8, 15); @x2 = (12, 10, 8, 9); print "main : @x1 \n"; print "main : @x2 \n"; &test(@x1, @x2); sub test { my (@arg1, @arg2) = @_; print "sub : @arg1 \n"; print "sub : @arg2 \n"; } 結果 main : 14 11 5 12 8 15 main : 12 10 8 9 sub : 14 11 5 12 8 15 12 10 8 9 sub : 引数1に全てが設定されて、引数2に設定されていない。

    • ベストアンサー
    • Perl
  • perlのcgiが動かない・・・

    cgiを組もうと思い、まずは簡単なもので試そうと思ったのですが、 うまくいかず困っています。 ↓プログラムは、こんな感じです。 ファイル名:index.cgi #!/usr/bin/perl print "<html>"; print "<body>"; print "abc"; print "</body>"; print "</html>"; <やってみたこと> ・Perlのパス「#!/usr/bin/perl」 が間違っていないか? which perl で /usr/bin/perl とでます。 ・Apache の設定が正しく行なわれているか? http://localhost でindex.htmlがきちんと表示できています。 ・「hello.cgi」 の設置場所を間違っていないか? プログラムソースが出るということは、 間違っていないのではないでしょうか? ・ためしに実行してみた TELNETで ./index.cgi <html><body>abc</body></html> とでてきました。 これはちゃんと動いているのでは?? 何か勘違いしていますか? お気づきの点を教えてください。よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • bad interpreter:エラーについて

    -bash: ./test.pl: usr/bin/perl: bad interpreter: というエラーについてです。 掲題のエラーが出てしまい、perlが動かないので困っています。 どうすればいいのか教えてもらえませんでしょうか。 【状況】 VMwareplayer3.1.2上で、CentOS5.5を動かし、デフォルトで入っているperlを使ったファイル「test.pl」を作っています。 test.plを実行しようとしているのですが、以下のエラーメッセージが表示されます。 -bash: ./test.pl: usr/bin/perl: bad interpreter: そのようなファイルやディレクトリはありません 実行した際のコマンドは./test.plです。 test.plの中身は以下。 ------------------------------------------------------ #!/usr/bin/perl use strict; use warnings; my $name = "morifuji"; print "Hello ". $name . "\n"; ------------------------------------------------------ 【確認済み事項】  test.plの置き場所は/usr/bin/perlです。  ls -lで権限をみたところ、rwxr-xr-x furukawa root 4096となっている。  perl test.plと命令するとエラーは返らずちゃんと表示されます。  (perlを省いて、test.plと命令するとエラーになる。これだと、webから表示されたときに動きません)  FTPとかで転送すると文字コードの問題でバグが出る、という風な記事を見かけたが、VMwarePlayerなのでそういったやりかたはしていない。  which perlと命令してperlの場所を探したが、 /usr/bin/ にある。

  • perl ファイルのデータを編集したい

    初めまして、perl をやり初めたばかりです。作業は Linux 上で行ってます。 あるテキストファイル data.txt があります。 data.txt の中は、以下のようになっているとします。 100 200 300 400 500 600 これを読み込んで、例えば、 1 2 3 4 5 6 以上の様に各数字を百分の一にして出力したいと思ってます。 一応、色々と調べながらプログラムを書いてはみましたが 思う様に出力されません。以下そのプログラム。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); $ref_x = \@x; $n_data = @x; for ($i = 0; $i< $n_data; ++$i) { $$ref_x[$i] /= 100 ; print $x[$i], " "; } print"\n"; どなたか、perl にお詳しい方教えていただけないでしょうか? 宜しくお願い申し上げます。

  • Perlで use strict して our変数

    Perl 初心者です。初めて質問します。 test_sub.pl で宣言した変数を test_main.pl から参照したくて悩んでいます。 環境 : WindowsXP / ActivePerl 5.14.2 -------------------- * test_sub.pl -------------------- #!/usr/bin/perl use strict; our $hoge = 'HOGE'; 1; -------------------- * test_main.pl -------------------- #!/usr/bin/perl use strict; require 'test_sub.pl'; print "Content-type: text/html\n\n"; print $hoge; -------------------- これを実行すると、 Global symbol "$hoge" requires explicit package name at C:/public_html/cgi-bin/test_main.pl line 7.\r というエラーが出ます。 require する前に、test_main.pl のほうで our($hoge); と宣言したり 参照する際に print $main::hoge; とパッケージを指定したりすればいけるのですが、 これらをしないとできないものなのでしょうか。 use strict; を書かなければ最初のソースでも動くのですが use strict は書きたい… 継承のようなことをしたいのです。 ちなみに以下試してみたソースです。 -------------------- * test_main.pl -------------------- #!/usr/bin/perl ######################################## # NG use strict; require 'test_sub.pl'; print "Content-type: text/html\n\n"; print $hoge; ######################################## # OK our変数を宣言しておくといける =pod use strict; our ($hoge); require 'test_sub.pl'; print "Content-type: text/html\n\n"; print $hoge; =cut ######################################## # OK 参照する際にパッケージ名を指定すればいける =pod use strict; require 'test_sub.pl'; print "Content-type: text/html\n\n"; print $main::hoge; =cut ######################################## ######################################## # NG =pod use strict; use base qw(test_sub); print "Content-type: text/html\n\n"; print $hoge; =cut ######################################## -------------------- * test_sub.pm -------------------- #!/usr/bin/perl package test_sub; use strict; our $hoge = 'HOGE'; 1; -------------------- NG パタンはどちらも Global symbol "$hoge" requires explicit package name のエラーとなります。 もしご存じの方がいらっしゃいましたら教えてください。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • このプログラムなんですが

    #! /usr/bin/perl @data=<>; open (IN,"newtype.txt"); @file = <IN>; close (IN); foreach $address (@file) { ($pn,$ad) = split(/\t/,$address); $pnad{$pn}=$ad; } foreach $jusyo (@data) { chomp $jusyo; print $jusyo; print "\n"; print "$pnad{$jusyo}"; } foreach $line (@file) { @data = split(/t\/, $line); if($data[0] =~ "51105") { print "$data[0]"; print "$data[1]"; } elsif($data[0] =~ "651130") { print "$data[0]"; print "$data[1]"; } } exit; コンパイルするときには ./sample.pl data.txt をシェルにうって実行します。 このプログラムでは、はじめに自分で指定したファイル内に存在する郵便番号(通常は7桁だけなんですが、プログラムを見ていただければわかると思われますが、それ以外に5桁(たとえば12354XX,x12354x,xx12354など))と6桁(134567x,x134567など)がありまして、それを表示させたいんですが、上のプログラムでは、if文以下の5桁と6桁があった場合にそれを同時に表示させるプログラムができていないんです。 ハッシュをもちいてプログラムを作り直したいんですが、教えてください。 今日の夜8時までに出さなくてはいけないので、すぐに回答をいただけたらありがたいです。

  • エラー表示

    CGIがエラーを出すと、サーバーが500番エラーを表示しますよね。 そのページを.htaccessのErrorDocumentを使って、自分で定義したものにできたのですが、そのエラーページをCGIにして、どこかにエラーになったページが吐いたエラー出力が入ってないかと思ったのですが、入ってないのでしょうか? -------- #!/usr/bin/perl # hoge.cgi # エラーするCGI die "hoge!"; -------- #!/usr/bin/perl # error.cgi # 500エラーページなCGI print "$_: $ENV{$_}<br>\n" foreach(sort keys %ENV); # ここでもない print foreach(<STDIN>); # ここでもない print foreach(<STDERR>); # ここでもない print ・・・どこかに "hoge!" が入ってないでしょうか? -------- # .htaccess ErrorDocument 500 /error.cgi Apache/1.3.24 Server perl 5.005_03 built for sun4-solaris

    • 締切済み
    • CGI

専門家に質問してみよう