ファイルを編集するのにforeachで@allbodyを1行ずつ調べているとします。
foreach $line (@allbody){
$iを含む行があれば$tmpと入れ替えてファイルへ保存
if ($line =~ /$i/){
$line =~ s/.*/$tmp;
print FILE @allbody;
}
でも$iを含む行がなければ、新しく追加書き込みをしたい
で、上に続けて
else {
push (@allbody,$tmp);
print FILE @allbody;
}
}
とやると、おかしい事なりますよねぇ
どうすればいいのでしょう?
No.2ベストアンサー
- 回答日時:
「$iを含む行がなければ」というのは、@allbody 全体を調べた後でなければ判断できませんよね。
なのに、それが foreach のブロック内にあるのは間違いです。こういう場合は「$iを含む行があったか」というフラグ用の変数をループ前に用意しておき、ループ内で条件が満たされればフラグを立て、ループ後にそれをチェックする、という方法を取ります。
また、foreach で1行ずつ調べているのに、「print FILE @allbody;」で全行書き出すのもおかしいですね。1行ずつ見ているのだから「print FILE $line;」のようにその行だけを出力するか、最後に @allbody を1度に出力すべきです。
以上をまとめるとこんな感じ。
$changed = 0; # $tmp との入れ替えフラグ
foreach $line (@allbody) {
if ($line =~ /$i/) {
$line =~ s/.*/$tmp/; # @allbody の内容にも反映されます。
$changed = 1;
}
}
if (!$changed) {
push @allbody, $tmp;
}
print FILE @allbody;
※コード内に全角空白を使っているので、コピーする場合はタブ等に置き換えてください。
なお、データ形式については書かれていませんが、恐らく @allbody の各行の末尾には改行が入っていることと思います。その場合、$tmp との入れ替えと追加で下記のような違いが生じてしまいます。
・push(@allbody,$tmp); # @allbody に「$tmp」が追加される。
・$line =~ s/.*/$tmp/; # その行の内容が「$tmp\n」となる。
これは正規表現の「.」が(通常は)改行にマッチしないため、「s/.*/$tmp/」では改行以外の部分を $tmp に置き換えることになってしまうからです。ですので、そこは置換ではなく、「$line = $tmp;」のように代入に変えた方が良いでしょう。
※上記は、$tmp が末尾に改行を含んでいる場合です。含んでいない場合は、置換は「$line = "$tmp\n";」、追加は「push(@allbody,"$tmp\n");」としてください。
蛇足ついでに書きますが、もしデータ量が多い場合は「$iを含んでいるなら」という条件を、正規表現($line =~ /$i/)から文字列操作(index($line,$i) != -1)に変えるだけで圧倒的に速くなります。
アドバイスありがとうございます
$i=0;とか$i=1;とかの意味は分かっていても使い方が今いち釈然としてなかってので、使った事なかったのですが、おかげでとても理解できました。とても便利なんで、これから使うようにします。
$tmpにすでに改行を含んであるので、$iを含む行を発見したらchompで改行を取り除いてから入れてましたが、そんな面倒な事しなくても素直に$line=$tmp;でよかったんですね‥‥なるほど‥‥
色々とレベルアップできました!
例文(?)まで書いてもらって、ありがとうございました。とても助かりました。
低レベルですが、これからもまたちまちま頑張って行こうと思います。
No.1
- 回答日時:
やりたいことの意図が不明ですが、
ファイルへの書き込みは1回限りであるという前提で良いでしょうか。
とすれば、
$iを含む行があれば$tmpと入れ替えてファイルへ保存後、
終了するようにします。$iを含む行がなければ、foreachのループの後に制御が移りますので、そこで、ファイルへの書き込みをします。
回答ありがとうございます
説明力がなくてすみません‥‥くぅ
でもこちらの意図は伝わっていたようで安心です
で、foreachの中で2つとも処理しようとしていたのが間違いだという事で、なるほどとても納得しました!
助かりました。ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP 値の取り出し方について教えて下さい。 1 2023/03/31 13:30
- Excel(エクセル) エクセルのマクロについて教えてください。 1 2023/02/11 11:05
- Excel(エクセル) エクセルのマクロについて教えてください。 1 2023/02/06 13:01
- その他(プログラミング・Web制作) セレクトボックスで選択された値をコントローラーで使用したい 2 2022/07/26 16:41
- Excel(エクセル) エクセルVBAでオブジェクトが必要です 2 2022/09/10 16:37
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
- PHP $filePath = './user_img/' . $file['name'];? 1 2022/12/10 07:29
- その他(プログラミング・Web制作) Pythonを勉強しています。 5 2023/08/25 09:51
- CGI htmlからパラメータで、cgiに渡したい。 1 2023/02/06 16:15
- Visual Basic(VBA) ExcelのVBAコードについて教えてください。 2 2023/05/23 16:28
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エラーチェック、ファイルに特...
-
cgiのログの書き方
-
perlでcsvファイルを読む(ダブ...
-
Perlで特定行から特定行までを...
-
csvデータの開始行と最終行を全...
-
python renameについて
-
VBAで巨大なファイルの途中から...
-
batファイルでrenameができませ...
-
Perlでのファイル出力における...
-
csvファイルの横方向への改行に...
-
VBAでCSVファイルの特定行を書...
-
Pythonでegrep機能をつかいたい
-
awkスクリプトでダブルクォーテ...
-
csv出力
-
VBAでCSVファイルを途中行まで...
-
VB6.0でDB接続する際に切断時の...
-
ディレクトリ名を取得したい
-
FindFirstFileとFindNextFileで...
-
ファイルの一部を別のファイル...
-
ListBoxのデータを高速でファイ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Perlで特定行から特定行までを...
-
Perlの初心者です。2重ループ...
-
ディレクトリ内のtxtファイル中...
-
Perlで空白行を削除
-
perlでcsvファイルを読む(ダブ...
-
Perlを利用してテキストフ...
-
ファイルの3行目までを出力したい
-
foreachの制御
-
Java CSVファイルをカンマごと...
-
Argument "\\\\n" isn't numeri...
-
エラーチェック、ファイルに特...
-
CSVデータの編集の際の重複チェ...
-
FTP接続時失敗時、接続先名をcs...
-
CSVファイルのデータの行数を取...
-
cgiのログの書き方
-
MATLAB std::exceptionエラー
-
VBAでCSVファイルを途中行まで...
-
awkスクリプトでダブルクォーテ...
-
VBAでCSVファイルの特定行を書...
-
バッチファイルの作り方(CSV→...
おすすめ情報