• 締切済み

ファイルへの追加書き込みについて

こんにちは。Perlを勉強しはじめた者です。 test1.plファイルにtuika.plを起動することで追加書き込みをしようとしているのですが、 その書き込みをプログラムの途中に行おうとしています。 内容としては、test1.plが文字置換を行うもので、その候補をtuika.plで入れてやります。 tuika.pl #!/usr/local/bin/perl use strict; use vars qw($oldword $newword); print "置換元の単語は? \n"; $oldword = <STDIN>; print "置換後の単語は? \n"; $newword = <STDIN>; open (FH, ">>test1.pl") or die "error $!\n"; seek FH, -47, 2; print FH "s/$oldword/$newword/og;\n"; close FH; seek関数は実際には途中書き込みには対応していない(?)ようなので、書き込みが末尾にきてしまい、うまくいきません…。 初心者な質問で申し訳ありませんが、なにか解決策がございましたら、ご教授願います。

  • Perl
  • 回答数5
  • ありがとう数1

みんなの回答

回答No.5

>> seek関数は実際には途中書き込みには対応していない(?)ようなので、書き込みが末尾にきてしまい、うまくいきません…。 seek関数は操作対象になる場所を変えるだけですよ。 書き込みが末尾になるのは追記モードでファイルを開いているから。 seek使って途中を変えて意図した通りになるかはわかりませんが多分ならないのでは。 途中を変えるという事は、後ろに有効なデータが残っているという事ですよね。 置換前と置換後の文字列長が違う場合には処理が必要ですよ。 ※置換後が長いと置換によって元のデータを上書きする事になる部分があるだろうし、逆だと古い文字列の一部が残るでしょうし。 要するに、長さが違う場合には別途処理が必要になるかも知れません。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

>s/女性/女/og; >  ←この部分に追加していきます。 >print $ofh $_; +>でopen→seekで移動→ファイルに出力 とすると、テキストエディタで言うところの「上書き/置換モード」になります。 うしろが自動でずれてくれる「挿入モード」ではありません。 ・ずらす分を変数に取り込み→挿入する分を出力→退避していた分を出力 ・全部取り込み→挿入する分を適切な箇所に挿入→全部出力 ・単純な追記で済むように、方法自体を変更する (「設定ファイル」として出力→test1.plは「設定ファイル」にしたがって置換する 等) といった工夫が必要です。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

#2 で言われているのはそういうことじゃない. 「丸ごと全部上書き」の意味が理解できていない? 余談だけど今のプログラムでひっかかるところを 2点ほど突っ込んでおこう. 1. そもそも今のパターンだと置換がうまくいかないと思うんだけど, そこは大丈夫? <STDIN> から読み込んだあとで chomp しないと, 入力を確定するための改行も入っちゃうよ. 2. その形だと s/// の o は役に立たないと思う.

  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.2

">>"でオープンすると、追記しかできません。 seekするのなら、読み書き可なモード「+>」でオープンしてください。 ただし、 > seek FH, -47, 2; これでは、SEEK_ENDから47バイト前がちょうどよい書き込み位置であるという保証はありませんし、 書き込む文字数が元より短い場合、残りは元々あった文字列が残ってしまいますので、 望み通りの結果にするのはかなり難しいと思います。 手軽に実現するなら、 ・test1.pl では、冒頭で「require "test2.pl"」とでもしておく ・test1.pl では、置換そのものは「$_=test2($_);」といった形で関数呼び出しを埋め込んでおく ・tuika.pl では、test2.plを丸ごと全部上書きを行うようにする。 ・test2.pl への出力内容は、「sub test2 { $_[0] =~ s/$oldword/$newword/og; }」という関数定義の形にする といった形が楽かと思います。

keyaki123
質問者

補足

遅くなりまして申し訳ありません。回答ありがとうございます。 +>だと、test1.plがs/$oldword/$newword/og;だけのファイルになってしまい、悩んでいたのですが、もう一度勉強し直してきます。 Tacosan様への回答と被るのですが、 s/女性/女/og;   ←この部分に追加していきます。 print $ofh $_; } close $ofh; close $ifh; } この場合、s/$oldword/$newword/og;\n を追加としてやれば後ろからの47バイトは動かないかなとも考えたのですが、ご指摘のとおり不安定な動作となりそうですね。 ご提示くださった手法ですが、 >>tuika.pl では、test2.plを丸ごと全部上書きを行うようにする。 >>test2.pl への出力内容は、「sub test2 { $_[0] =~ s/$oldword/$newword/og; }」という関数定義の形にする ここは、tuika.plでtest2.plに対して「sub test2 { $_[0] =~ s/$oldword/$newword/og; }」を追加上書き保存していき、それをtest1.plで実行してやるという形ということでしょうか?

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「データをファイルの途中に書き込む」のはいいとして, 元のファイルにあった「それ以降のデータ」はどうするつもり?

keyaki123
質問者

補足

遅くなりまして、申し訳ありません。回答ありがとうございます。 それ以降のデータといいますと、 s/$oldword/$newword/og;\n を追加した後ろのデータのことでしょうか? 目指していたものは、置換するデータを蓄積していって、test1.plを実行した際に、一括置換するものでしたが、 while (<$ifh>) { s/男性/男/og; s/女性/女/og;   ←この部分に追加していく感じです。 print $ofh $_; } この手法だとprint以下がダブったり消えたりしてしまうのでしょうか?

関連するQ&A

  • 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
  • CGIで外部ファイルに書き込みができません

    Perl初心者です。 外部テキストファイルに、HTMLのフォームで入力した情報を書き込み、それを読み込んでHTMLで表示するコードをつくろうとしているのですが、外部ファイルに書き込みができません。(読み込みはできます) コードは以下のとおりです。 #! /usr/bin/perl use strict; my $self = "test.cgi"; my $str = <>; my $filename = "log.txt"; open FH,">$filename"; print FH $str; close FH; my $body; open FH,"<$filename"; my $str2 = <FH>; $body = $str2; close FH; print "Content-type: text/html\n\n"; print <<Q; <html> <head><title>jjj</title></head> <body> <form action = "$self" method = "POST"> <input type = "text" name = "data01" /> <input type = "text" name = "data02" /><br> <input type = "submit" value = "soushinn" /> <hr/> $body </form> </body> </html> Q 環境はMac OS 10.4.11、Apacheを起動して、ローカルでテストしています。 パーミッション等、いろいろ試しましたが、なぜ書き込めないのかよく分かりません。 どなたか原因を教えていただけないでしょうか。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • qw( )空白区切りの仕組み

    再び基本的なことでお伺いします。 qw( ) という関数?があると思うのですが、 これを使うときの考え方と言いますか、特徴を教えて頂きたく、 現在の見解を書いてみます。 間違った理解がありましたら、ご指摘ください。 (1)qw は空白区切りの要素を返す。 @ans = qw(あ い う え お); @ans = split(/\s+/,"あ い う え お"); #double-quote は、何れも同じ@ansが求まる。 →この場合、qwとsplitとどちらを使うかは、好みの問題ですか? こちらが良いという理由があれば教えてください。 (2)qw() と qw// の違い。 @ans = qw(あ い う え お); @ans = qw/あ い う え お/; は、何れも同じ@ansが求まる。 →これらもどちらでもOKですか?どのように使い分けるのでしょう。 (3)同様に(ややくどいですが;;)変数名を使った場合、 $a=1; $i=2; $u=3; $e=4; $o=5; $"=","; @ans = qw($a $i $u $e $o); print "@ans\n"; @ans = qw/$a $i $u $e $o/; print "@ans\n"; @ans = split(/\s+/,'$a $i $u $e $o'); #single-quote print "@ans\n"; -------------------------------- これらは、何れも同じ答えになりましたが、 決定的な違いなどがありましたら、教えてください。 (4)上記に関連して、useなどとの組み合わせにて、 use vars qw( $x ); と書くことと use vars '$x'; と書くことの違いはあるのでしょうか。 以上、よろしくお願いします。

    • ベストアンサー
    • Perl
  • perl の printでのファイルへの指示にて

    独学でmacでパールを勉強しています。 始めてからまだ1週間くらい。 教科書みながら、print命令でファイルハンドルに指示を出してるのですが、 書き込めはできるのですが、 ファイルが無い場合、 新規に自動でファイルが作成されるはずとの記載があったのですが、 何故か、自動でファイルが生成されません。 調べても、設定が必要等言われてますが、 mac自体も初心者でほとんどわかりません。 どのような設定にすればいいのでしょうか? また、ソースに何か悪い所があるのでしょうか? お助けください。   ちなみに下記がソースです。 ーーーーーーーーーーーーーーーーーーーーーーーーーーーー #!/usr/bin/perl print "Content-type: text/html\n\n"; print "<HTML>\n"; print "<HEAD><TITLE>アクセスカウンタ</TITLE></HEAD>\n"; print " <BODY>\n"; print "<H1>test</H1><HR>\n"; if ( open ( FH , "count.txt")){ $cnt = <FH>; close( FH ); $cnt++; print"<CENTER>あなたは${cnt}人目の訪問者です。</CENTER>\n"; if ( open(FH, ">count.txt" )){ print FH $cnt; close(FH); } else { print "ファイルの書き込みオープンに失敗しました。\n"; } } else { print "ファイルの書き込みオープンに失敗しました。\n"; } print "</BODY>\n"; print "</HTML>\n"; __END__ ーーーーーーーーーーーーーーーーーーーーーーーーーー

    • ベストアンサー
    • Perl
  • Perl ファイルハンドルを閉じずに反映させる

    お世話になっております。 Perl(プログラミング言語)について質問です。 openメソッドで開いたファイルハンドルに print文で書込みを行った際に、ファイルハンドルをcloseせずに、 書込みを反映させる方法はありますか? 開くのはファイルではなく(他プロセスへの)パイプです。 $| を設定してもだめでした (例としては perl1.pl , perl2.pl を用意する <perl1.pl> $i; open(OUT,"| perl2.pl") while(1){ print OUT "$i" $i++  } close(OUT) <perl2.pl> while( <STDIN> ) { print $_; } のようなことをやりたいです。 上記のようなスクリプトを実行したところ、 perl1のcloseが実行されるまで反映されません。 これをcloseをせずに反映させる方法はありますでしょうか? よろしくお願いします。

    • ベストアンサー
    • Perl
  • Perlのファイルのアップロードの方法についてお聞きします。

    Perlのファイルのアップロードの方法についてお聞きします。 &ReadParseを用いた方法で、 $file = $in{'TENSOU'};で$file自体にデータが入るので 簡単だなと思っていましたが、送信元と送信後のファイルが若干違っていました。 使い方が間違っているのでしょうか? 以下、サンプル ◆HTML側 <FORM ACTION="up.cgi" ENCTYPE="multipart/form-data" METHOD="POST"><P> ファイル: <INPUT TYPE="file" NAME="TENSOU" SIZE="32"><BR> <INPUT TYPE="submit" VALUE="送信"> </FORM> ◆Perl側 &ReadParseの例を用いた方法 #!/perl/bin/perl #!/usr/local/bin/perl use CGI; use CGI::Carp qw(fatalsToBrowser); #--->エラー対策 require 'cgi-lib.pl'; require 'jcode.pl'; $BUFSIZE = 2048; &ReadParse; # ==> 強力な変換 $file = $in{'TENSOU'}; # ==> 実態自体がデータなので、取り扱いしやすい $file_size = length($file); $file_size *= ($BUFSIZE / 1024); open(OUT, "> test.jpg"); print(OUT $file); close(OUT); print "Content-type: text/html\n\n"; print "$file_size(KB)<br>\n"; print "<a href=\"test.jpg\">テスト</a>\n"; exit;

    • ベストアンサー
    • CGI
  • ファイルの先頭に追加書込みする方法について教えて下さい

    今まで、単にファイルの最後にデータを追加するように 下記のように書いていた部分を open(OUT,">>$logfile2") || &error; print OUT "カウント : \[ $pcount \]\n日  時 : \[ $time \]\n"; close(OUT); ファイルの先頭に追加していくようにしたいのですが、うまくいきません。 ミスティーネット・Perl・CGI講座というサイトを参考に下記のようにしてみました。 open(DATA,"+<$logfile2") || &error; seek(DATA,0,0); print DATA "\nカウント : \[ $pcount \]\n日  時 : \[ $time \]\n"; close(DATA); このように書くと追加書込みではなく、書き換えになってしまいます。 また、+<の部分を>>にすると変更前と同様、ファイルの最後に追加されてしまいます。 どこがどういけないのか判る方がみえましたら教えて下さい。 よろしくお願いいたします。

    • ベストアンサー
    • CGI
  • <STDIN>とARGVとの振る舞いの違いが分からず困っております。

    <STDIN>とARGVとの振る舞いの違いが分からず困っております。 Perlといいますか、プログラム初心者です。 現在、Perlでファイル処理を行おうと思っており、下記のようなスクリプトを書き、file_test.plとして保存・実行しようとしたのですが、実行時の命令の仕方により処理が出来たり出来なかったりで、困っております。どなたか、ご教授頂けませんでしょうか。 なお、使用環境はWindows XP, Active Perl 5.8.8です。 スクリプトのソース、読み込みファイル共にShift-JISです。 (ここには記載しておりませんが、処理後の吐き出しファイルはUTF-8になります) -------------------- file_test.plのソースファイル -------------------- use strict; use warnings; use encoding "cp932"; use Encode::Guess qw/euc-jp shiftjis 7bit-jis/; binmode STDIN, ':encoding(cp932)'; binmode STDOUT, ':encoding(cp932)'; binmode STDERR, ':encoding(cp932)'; my $csvname; if(defined($ARGV[0])){ $csvname = $ARGV[0]; print "csvname = $csvname\n"; #文字コード判定 my $enc = guess_encoding($csvname); ref($enc) or die "Can't guess: $enc"; print "encoding is ", $enc->name, "\n"; #UTF-8フラグチェック print utf8::is_utf8("$csvname") ? "UTF-8 Flag\n" : "not UTF-8 Flag\n"; } else{ print "input file: "; $csvname = <STDIN>; chomp($csvname); print "csvname = $csvname\n"; #文字コード判定 my $enc = guess_encoding($csvname); ref($enc) or die "Can't guess: $enc"; print "encoding is ", $enc->name, "\n"; #UTF-8フラグチェック print utf8::is_utf8("$csvname") ? "UTF-8 Flag\n" : "not UTF-8 Flag\n"; } open CSV, '<:encoding(sjis)', $csvname or die "$!"; print "FILE OPEN OK\n"; close(CSV); ------------------- file_test.plのソースファイル END ------------------- このソースを"perl file_test.pl csvfile.csv" で実行すると問題なく処理できます。 しかし、"perl file_test.pl" で実行し、あとからファイル名を入力すると、 "Invalid argument at file_test.pl line 35, <STDIN> line 1."というエラーが出ます。 (35行目はOPENコマンドの行です) しかし、 "perl -CA file_test.pl"と-CAオプションを入れ、後からファイル名を入力した場合、動作します(上述のファイルの実行と同時にファイル名を指定したものでも動きます)。 実際にはコマンドプロンプトからの実行ではなく、plファイルをダブルクリック、その後ファイル名を指定して処理を行いたいため、悩んでおります。 どのようにしたら、うまく実行できるか、ご教授頂ければ幸いです。

  • perlのDigest::MD5;でのMD5算出が異なる

    perlのDigest::MD5;でのMD5算出が異なる 下記、スクリプトをレンタルサーバ上と、WindowsOS上で走らせてみたところ、おなじファイルにも関わらず、MD5が異なります。 何故でしょうか? #!/usr/local/bin/perl use strict; use warnings; use Digest::MD5; my $file = 'test.zip'; my $ctx = Digest::MD5->new; open my $fh, "<$file"; $ctx->addfile($fh); my $md5 = $ctx->hexdigest; close($fh); open my $fh2, ">>md5.txt"; print $fh2 "$file $md5\n"; print "$file $md5\n"; close $fh2;

    • ベストアンサー
    • Perl
  • CSVファイルの処理方法

    PerlでCSVファイルの処理をしようとしています。 CSVファイル(ここではdata1.csvとします)の中身は、A列とB列に数値が1000行程表記されています。 -5,1 -4,2 -3,3  ・  ・  ・ 作成したPerlのファイル(ここではtest1.plとします)下のようにし、 while ($_=<stdin>){ print"$_\n"; } Cygwinコマンド上で、 $ perl test1.pl <data1.csv と入力すると、CSVファイル(data1.csv)の数値がCygwinコマンド上に全て表記されます。 前置きが長かったのですが、CSVファイル(data1.csv)の3行目までの数値だけをCygwinコマンド上に表記したい場合、どのようにプログラムすればよいのですか。 お願いします。

    • ベストアンサー
    • Perl

専門家に質問してみよう