重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

こんにちは。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関数は実際には途中書き込みには対応していない(?)ようなので、書き込みが末尾にきてしまい、うまくいきません…。
初心者な質問で申し訳ありませんが、なにか解決策がございましたら、ご教授願います。

A 回答 (5件)

>> seek関数は実際には途中書き込みには対応していない(?)ようなので、書き込みが末尾にきてしまい、うまくいきません…。



seek関数は操作対象になる場所を変えるだけですよ。
書き込みが末尾になるのは追記モードでファイルを開いているから。

seek使って途中を変えて意図した通りになるかはわかりませんが多分ならないのでは。

途中を変えるという事は、後ろに有効なデータが残っているという事ですよね。
置換前と置換後の文字列長が違う場合には処理が必要ですよ。
※置換後が長いと置換によって元のデータを上書きする事になる部分があるだろうし、逆だと古い文字列の一部が残るでしょうし。

要するに、長さが違う場合には別途処理が必要になるかも知れません。
    • good
    • 0

>s/女性/女/og;


>  ←この部分に追加していきます。
>print $ofh $_;

+>でopen→seekで移動→ファイルに出力
とすると、テキストエディタで言うところの「上書き/置換モード」になります。
うしろが自動でずれてくれる「挿入モード」ではありません。

・ずらす分を変数に取り込み→挿入する分を出力→退避していた分を出力
・全部取り込み→挿入する分を適切な箇所に挿入→全部出力
・単純な追記で済むように、方法自体を変更する
(「設定ファイル」として出力→test1.plは「設定ファイル」にしたがって置換する 等)
といった工夫が必要です。
    • good
    • 0

#2 で言われているのはそういうことじゃない. 「丸ごと全部上書き」の意味が理解できていない?



余談だけど今のプログラムでひっかかるところを 2点ほど突っ込んでおこう.
1. そもそも今のパターンだと置換がうまくいかないと思うんだけど, そこは大丈夫? <STDIN> から読み込んだあとで chomp しないと, 入力を確定するための改行も入っちゃうよ.

2. その形だと s/// の o は役に立たないと思う.
    • good
    • 0

">>"でオープンすると、追記しかできません。


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; }」という関数定義の形にする

といった形が楽かと思います。

この回答への補足

遅くなりまして申し訳ありません。回答ありがとうございます。

+>だと、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で実行してやるという形ということでしょうか?

補足日時:2010/12/06 17:40
    • good
    • 0

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

この回答への補足

遅くなりまして、申し訳ありません。回答ありがとうございます。
それ以降のデータといいますと、 s/$oldword/$newword/og;\n
を追加した後ろのデータのことでしょうか?
目指していたものは、置換するデータを蓄積していって、test1.plを実行した際に、一括置換するものでしたが、

while (<$ifh>) {
s/男性/男/og;
s/女性/女/og;
  ←この部分に追加していく感じです。
print $ofh $_;
}

この手法だとprint以下がダブったり消えたりしてしまうのでしょうか?

補足日時:2010/12/06 16:42
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!