これからの季節に親子でハイキング! >>

ある文字を検索して、その行を含む&1行前と2行後ろの行までを削除するスクリプトを書きたいのですが、上手くいきません。

検索して行番号を獲得して、
$rowという変数に入れました。
それをさらに
$a :1行前
$b :2行後ろの行番号に格納しました。

問題は削除するところが上手く行きません。
next if で $aから$bの行番号を削除して、と頼んでいるのですが、空のファイルに上書きされてしまいます。

お願いです。この方法で何が間違っているかを教えてください!

#!/opt/perl/5.8.0/bin/perl -w
print "Content-type: text/html\n\n";

use CGI qw(:standard);
use CGI::Carp qw/fatalsToBrowser/;

$filename = "../XML/link.xml";
$new = "../XML/link.xsl";

open(FILE, $filename) or die "Can't open `$filename': $!";
while (<FILE>) {
if($_ =~ /HRWeb/){
#print "$.";
$row = $.;
$a = $row-1;
$b = $row+2;

print "HRWeb delete rows $a through ";
}
}

&delete ($a, $b);

sub delete{


open( OLD, "< $filename" );
open( NEW, "> $new" );
while ( <OLD> ) {
next if /$a/../$b/; # copy everything but $a through $b
print NEW $_;
}print "$a deleted $b";

close( OLD );
close( NEW );
rename( $filename, "$filename.orig" );
rename($new, $filename );
}

このQ&Aに関連する最新のQ&A

A 回答 (6件)

>next if /$a/../$b/;


>これですね。こんな書き方はできません。
そうですね。
next if $.==$a..$.==$b;
とは書けます
    • good
    • 0
この回答へのお礼

ありがとうございます!
スクリプトに変数の指定意外変更する必要なく成功させることができました。
many many thanks です!

ですが、午前中ずっと葛藤を続けていて、コマンドラインでは上手く行くのに、ウェブサーバーからだと実行されなくて、午後にようやく、フォルダーの権限がwriteになっていないことが判明しました・・・

おっとっと。

お礼日時:2006/01/26 23:47

これは少し関係ないことですが…



> &delete ($a, $b);

こう書いていて sub delete の方で @_ を受け取らずにそのまま $a, $b を使うのは書き方が変です。(動かないわけではありませんが…)。

あと FILE の close() がありません。Perl なのでなくてもいいんですが、 close() されないままだとプログラムが終了するまでファイルディスクリプタを一つ使いっぱなしになると思うので、使い終わったらなるべく close() しておくのがおすすめです。

で、 delete の中ですが

> next if /$a/../$b/;

こうじゃなくてもっと普通に書けばいいのでは?
たとえばこう書くとか。

next if ($. >= $a && $. <= $b);
    • good
    • 0

>next if $a..$b;


>だと ($a, $b がどちらも数値ならば) 「$. が $a と $b の間 next を実行する」という意味.
間違い
「$. が A と B の間 next を実行する」という意味.
になるのは、整数"定数"の時
    • good
    • 0

next if /$a/../$b/;


じゃなくって
next if $a..$b;
なら動くかも.

蛇足: スカラーコンテキストにおける範囲演算子 .. の振舞い.

a .. b において
1) .. の前後がどちらも数値の場合は a <= $. && $. <= b の意味
2) そうでないときは「論理式 a が成り立ってから論理式 b が成り立つまで」の意味

next if /$a/../$b/;
という書き方は可能で「$a (に入っている正規表現) にマッチしてから $b (に入っている正規表現) にマッチするまで next を実行する」という意味.
next if $a..$b;
だと ($a, $b がどちらも数値ならば) 「$. が $a と $b の間 next を実行する」という意味.
    • good
    • 0
この回答へのお礼

はい、一番最初にこれを試していたのですが、やはり駄目でした。

ですが、わざわざ書き込みありがとうございました。
感謝です。

お礼日時:2006/01/26 23:43

とりあえず質問内容を元に自分で組んでみました。



$char = 'abc'; #対象文字列
$file = './file'; #ファイル

open(OUT, "> $file.tmp");
open(IN, "< $file");
$skip = 0;
$tmp = '';
while(<IN>){

if($skip){
$skip++;
if($skip == 4){$skip = 0;}
}else{
if(/$char/g){$skip = 1;}
if($skip == 0){print OUT $tmp;}
}

$tmp = $_;

}

if($skip == 0){print OUT $tmp;}

close(IN);
close(OUT);

rename("$file.tmp","$file");


> お願いです。この方法で何が間違っているかを教えてください!

next if /$a/../$b/;
これですね。こんな書き方はできません。
書くなら
unless($. <= $b && $. >= $a){print NEW;}
とか。(ちなみに$_は省略できます。)
    • good
    • 0
この回答へのお礼

どうもありがとうございます!!
このスクリプトでも上手く行きました。
ただ、私のような初心者ではどれが何言っているのか分からなくて、プロダクションで使うのにはリスキーだと思ったので、今回は辞めましたが、非常に参考になりました。

ありがとうございます。

お礼日時:2006/01/26 23:48

基本的には、コレで良いと思いますが、


FILE
がclose されずに、&delete でrename しようとしているので、
rename は、両方失敗してしまうと思います。

あと、カレントディレクトリが思う所になっているか、確認するといいと思います。
    • good
    • 0

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QPerlで特定行から特定行までを抜き出したい

皆さんのお知恵をお貸し頂ければ幸いです。

Perlで以下のようなことをしたいと考えています。
例えば、次のようなテキストファイルがあったとします。

example.log
==================================
aaaa
hogehoge
test
okok
perl
script
==================================

上記ファイルを読み込んで、「hogehoge」から「perl」の間に挟まれた行だけ抜き出したいのです。
イメージとしては、読み込んだファイルを配列に入れて、一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

このような場合、どういう風にすればいいのでしょうか?
恐れ入りますが、ご教授頂ければ幸いです。

それでは、どうぞよろしくお願い致します。

Aベストアンサー

> 一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

それでいいと思いますよ?これをそのままコード化すると、こんな感じでしょうか。(No.1さんのとはちょっと結果が違います。)

open FH, "example.log" or die $!;
$flag = 0;
while ($data = <FH>) {
  chomp $data;
  if  ($data eq "hogehoge") { $flag = 1 }
  elsif ($data eq "perl")    { $flag = 0 }
  elsif ($flag) { print "$data\n" }
}
close FH;

で、もっと略したいPerlな人だとこんな感じ。Perl独特の記法がふんだんに使われているので、勉強するには不向きかもしれませんが^^;

open FH, "example.log" or die $!;
while (<FH>) {
  print if /^hogehoge$/ .. /^perl$/ and !/^(?:hogehoge|perl)$/;
}
close FH;

※インデントに全角空白を使っているので、コピーする場合はタブなどに置換して下さい。

> 一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

それでいいと思いますよ?これをそのままコード化すると、こんな感じでしょうか。(No.1さんのとはちょっと結果が違います。)

open FH, "example.log" or die $!;
$flag = 0;
while ($data = <FH>) {
  chomp $data;
  if  ($data eq "hogehoge") { $flag = 1 }
  elsif ($data eq "perl")    { $fl...続きを読む

QPerlで行頭にある文字が含まれている行を全部削除して詰めたい

perl初心者です。以下のようにデータがならんでいる時、
test111 aaaaaaaaabbbbbbbbcccccc
test112 aaaaccccabbbbbbbbcccccc
test113 aaaaccaaabbbbbbbbcccccc
test114 acccaaaaabbbbbbbbcccccc

test111 aacaaaaaabbbbbbbbcccccc
test112 accaaaaaabbbbbbbbcccccc
test113 aaacccaaabbbbbbbbcccccc
test114 aaaaaccaabbbbbbbbcccccc

test112の行だけ削除して、さらにそこを詰めたい時のスクリプトを作成しています。

途中からわかりません。
行を削除する関数が調べても見つからないのです。

#!/usr/bin/perl ;
open(IN, "test.doc") or die ;

open(OUT, ">testout.doc");

while(<IN>) {
chomp ;
if (/(\S+)/) {

$name = $1 ;

if ($name =~ /^test112(\S+)/) {
#ここでマッチさせて、一気に行を削除して、しかも行を詰めたいのですが

;

}
print OUT " \n" ;
}
}
close (IN) ;
close (OUT) ;

大変困っております。宜しくお願いします。

perl初心者です。以下のようにデータがならんでいる時、
test111 aaaaaaaaabbbbbbbbcccccc
test112 aaaaccccabbbbbbbbcccccc
test113 aaaaccaaabbbbbbbbcccccc
test114 acccaaaaabbbbbbbbcccccc

test111 aacaaaaaabbbbbbbbcccccc
test112 accaaaaaabbbbbbbbcccccc
test113 aaacccaaabbbbbbbbcccccc
test114 aaaaaccaabbbbbbbbcccccc

test112の行だけ削除して、さらにそこを詰めたい時のスクリプトを作成しています。

途中からわかりません。
行を削除する関数が調べても見つからないのです。

...続きを読む

Aベストアンサー

一致しなかったときのみ出力するということで、

while(<IN>){
unless(/^test112/){
print OUT;
}
}

更に簡単に書くと、
while(<IN>){
print OUT unless(/^test112/);
}
となります。

削除にこだわるなら、
while(<IN>){
s/^test112\s.+//;
print OUT;
}
あたりでしょうか。

もしくは、明示的に削除したいなら、
while(<IN>){
if(/^test112\s.+/){
$_ = "";
}
print OUT;
}
というふうに、カラの文字列を代入してやるのも、値を削除するときの常套手段ですね。

QPerlで空白行を削除

現在、Perlにて外部のcsvファイルを読み込み、"重複行"と"空白行"を削除するプログラムを作成しています。
重複行を削除する部分は
------
open(IN, "csvtime.csv");
@data = <IN>;
close(IN);

@data = grep {!$count{$_}++} @data;

open(OUT, "> csvtime.csv");
print(OUT @data);
close(OUT);
------
でできたのですが、空白行を削除する部分がわかりません。
申し訳ないのですが、お教えいただけないでしょうか。

また、空白行で最初の空白行は残すようにしたいです。
よろしくお願いいたします。

例)
読み出しデータ
-----
(ヘッダ1行目)
(ヘッダ2行目)
(ヘッダ3行目)
(必要な空白)
(ヘッダ4行目)
00:00:00,302
00:01:00,274
00:02:00,272
00:03:00,248


00:04:00,237
00:05:00,239
00:05:00,239
00:06:00,256

00:07:00,260
00:08:00,250
00:09:00,253
00:10:00,241
-----

加工後データ
-----
(ヘッダ1行目)
(ヘッダ2行目)
(ヘッダ3行目)
(必要な空白)
(ヘッダ4行目)
00:00:00,302
00:01:00,274
00:02:00,272
00:03:00,248
00:04:00,237
00:05:00,239
00:06:00,256
00:07:00,260
00:08:00,250
00:09:00,253
00:10:00,241
-----

現在、Perlにて外部のcsvファイルを読み込み、"重複行"と"空白行"を削除するプログラムを作成しています。
重複行を削除する部分は
------
open(IN, "csvtime.csv");
@data = <IN>;
close(IN);

@data = grep {!$count{$_}++} @data;

open(OUT, "> csvtime.csv");
print(OUT @data);
close(OUT);
------
でできたのですが、空白行を削除する部分がわかりません。
申し訳ないのですが、お教えいただけないでしょうか。

また、空白行で最初の空白行は残すようにしたいです。
よろしくお願いいたします。

例)
読...続きを読む

Aベストアンサー

あれ、このコードで空白行削除されませんか?

読み出しファイルの「(必要な空白)」って最初の空白行ですよね?

>@data = grep {!$count{$_}++} @data;
これはハッシュに存在しないものだけ配列に格納してるんで、最初の空白行だけに整形されるはずですが。

空白行にひとつ以上のタブや半角・全角スペース文字が来たりしてたら動作しないとは思いますが。


人気Q&Aランキング