• ベストアンサー

行を指定して削除する方法PERL

ある文字を検索して、その行を含む&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 ); }

  • Perl
  • 回答数6
  • ありがとう数6

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

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

>next if /$a/../$b/; >これですね。こんな書き方はできません。 そうですね。 next if $.==$a..$.==$b; とは書けます

manami921
質問者

お礼

ありがとうございます! スクリプトに変数の指定意外変更する必要なく成功させることができました。 many many thanks です! ですが、午前中ずっと葛藤を続けていて、コマンドラインでは上手く行くのに、ウェブサーバーからだと実行されなくて、午後にようやく、フォルダーの権限がwriteになっていないことが判明しました・・・ おっとっと。

その他の回答 (5)

回答No.6

これは少し関係ないことですが… > &delete ($a, $b); こう書いていて sub delete の方で @_ を受け取らずにそのまま $a, $b を使うのは書き方が変です。(動かないわけではありませんが…)。 あと FILE の close() がありません。Perl なのでなくてもいいんですが、 close() されないままだとプログラムが終了するまでファイルディスクリプタを一つ使いっぱなしになると思うので、使い終わったらなるべく close() しておくのがおすすめです。 で、 delete の中ですが > next if /$a/../$b/; こうじゃなくてもっと普通に書けばいいのでは? たとえばこう書くとか。 next if ($. >= $a && $. <= $b);

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.5

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

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

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 を実行する」という意味.

manami921
質問者

お礼

はい、一番最初にこれを試していたのですが、やはり駄目でした。 ですが、わざわざ書き込みありがとうございました。 感謝です。

  • Ethersky
  • ベストアンサー率71% (168/235)
回答No.2

とりあえず質問内容を元に自分で組んでみました。 $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;} とか。(ちなみに$_は省略できます。)

manami921
質問者

お礼

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

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

基本的には、コレで良いと思いますが、 FILE がclose されずに、&delete でrename しようとしているので、 rename は、両方失敗してしまうと思います。 あと、カレントディレクトリが思う所になっているか、確認するといいと思います。

関連するQ&A

  • VBAでの行削除について

    教えてください。 現在、VBAを使用して、CSVファイルの編集をしたいと考えています。 フォルダ内に数個のCSVファイルがあり、それらにすべて同じ処理(行削除など)をしたいのです。 下記のようなプログラムです。 Sub getting() Dim myPath As String Dim myFName As String Dim FCnt As Integer Dim A(500) As String MsgBox CurDir() Workbooks("自動処理.xls").Activate myPath = ActiveWorkbook.Path MsgBox myPath ChDir myPath FCut = 0 myFName = Dir("*.csv") If myFName <> "" Then FCut = FCut + 1 A(FCut) = myFName Do myFName = Dir() If myFName <> "" Then FCut = FCut + 1 A(FCut) = myFName MsgBox A(FCut) Else Exit Do End If Loop End If MsgBox "「" & myPath & "」には、" & FCut & "個のファイルがあります。" Dim i As Integer Dim seet As String Dim ws As Object Dim FullPath As String For i = 1 To 1 seet = Left(A(1), 6) FullPath = myPath & "\" & A(i) 'Workbooks.Open(FullPath).Activate Open FullPath For Append As #1 Print #1, Rows("1:1").Select Selection.Delete Shift:=xlUp Rows("2:2").Select Selection.Delete Shift:=xlUp Range("A1").Select Print #1, Range("A1").Value = "" Print #1, Range("A1").Value = "COMP_NAME" Print #1, Range("B1").Select Print #1, ActiveCell.Value; "PC_OS" Print #1, Range("C1").Select Print #1, ActiveCell.Value = "OS_SUB_VERS" Print #1, Range("D1").Select Print #1, ActiveCell.Value = "IP_ADDR" Print #1, Range("E1").Select Print #1, ActiveCell.Value = "LOCATION " Close #1 ' Workbooks(A(i)).Save ' Workbooks(A(i)).Close savechanges:=False  Next i End Sub 教えていただきたいのは、どうにかworkbook.openを使わず、ファイルを編集できるところまでいったのですが、ファイルを開かずに行を削除することができません。   >Print #1, Rows("1:1").Select >Selection.Delete Shift:=xlUp >Rows("2:2").Select >Selection.Delete Shift:=xlUp ファイルを開かずに行削除をできるものなのでしょうか。 ご存知の方がいれば教えてください。 よろしくお願いいたします。

  • 二つの条件を満たす行を削除の方法教えて下さい(><)

    エクセルは基本的な事しか分からないのですが、 どうしても仕事で必要で、土日に持ち帰ってきたのですが うまくできません。どなたか教えて下さい。 A B C D 1 3 2 1 4 2 2 2 3 2 2 1 5 4 4 1 3 4 5 2 2 1 2 ちょっと見づらいですが、上記のような表があるとして A列が2 かつ C列が2の行を削除したいです。 条件がひとつだと For R = Cells(Rows.Count, "A").End(xlUp).Row To 2 Step -1 If Cells(R, "A").Value <> "" ThenIf Cells(R, "A").Value = 2 Then 'Rows(R).Delete xlShiftUp End IfEnd IfNext R で消せたのですが、二つだとうまくいきません。 どなたか教えて下さい。よろしくお願いいたします。

  • VBAで空白行を削除する

    VBAでリストの空白行を削除するための適当なコードを探しているのですがどんぴしゃのものが中々見つかりません。ご教授下さい。 ブックBのシートBのリストにはA2~AN●まで値が入っています。 別のブックAからVBAで値を取り出し貼り付けています。 いくつかの方法を試しました。 (1)ブックを開いたときに空白行を削除 Sub Auto_Open() '空白行を削除 Dim lRow As Long Dim i As Long lRow = Cells(Rows.Count, 1).End(xlUp).Row Application.ScreenUpdating = False For i = lRow To 2 Step -1 If Cells(i, 1).Value = "" Then Range(i & ":" & i).Delete End If Next i Application.ScreenUpdating = True End Sub 5分以上砂時計のままで結局終わりません。 強制終了させ再度ブックを開くと空白行は削除されているのですが、こんな動作では使うことができません。 (2)ブックAの値を貼り付けた後、空白行を削除し上書き保存する Sub エクスポート() Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Range(Cells(5, 7), Cells(79, 46)).Select Selection.Copy 'コピー Workbooks.Open Filename:="\\パス\ブックB.xlsm" '貼り付け先ファイルオープン Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _ :=False, Transpose:=False '貼り付け Dim lRow As Long Dim i As Long lRow = Cells(Rows.Count, 1).End(xlUp).Row Application.ScreenUpdating = False For i = lRow To 2 Step -1 If Cells(i, 1).Value = "" Then Range(i & ":" & i).Delete End If Next i Application.ScreenUpdating = True  '空白行を削除 ActiveWorkbook.Save '上書き保存 Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub (3)空白行を削除の部分は以下のコードも試しました Worksheets("SheetB").Range("A1").Select Set currentCell = Worksheets("sheetB").Range("A1") Do While Not IsEmpty(currentCell) Set nextCell = currentCell.Offset(1, 0) If Not IsEmpty(currentCell) Then 'カレントセルが空白でなく、 If IsEmpty(nextCell) Then '次のセルが空白のとき nextCell.EntireRow.Delete End If End If Set currentCell = currentCell.Offset(1, 0) Loop '空白行削除 宜しくお願い致します。

  • Perlで行をさかのぼって削除する方法を教えて下さい

    ActivePerl5.8.4にて、以下の規則に従い、テキストファイルから複数行を削除しようとしています。 ・1つの行はアルファベットと数字から成っており、アルファベットはA,B,Cの順に出現する。A,B,Cの行で一かたまり。 ・数字部分が全く同じかたまりが出現すると、後で出現したかたまりを削除する。 ・数字部分が全く同じかたまりが出現するときは、必ず連続で出現する。 下のような感じです。(スペースの都合で「\n」をつけましたが、実際には改行までが1行に書かれているテキストファイルを読み込みます。) 【入力】 A 1\nB 2\nC 3\nA 1\nB 2\nC 3\nA 1\nB 2\nC 2[EOF] 【出力】 A 1\nB 2\nC 3\nA 1\nB 2\nC 2[EOF] すぐに思いついた方法はこんな感じです(まだ勉強不足のため、コードではあらわせません)。  1.ファイルの1行ずつ読み込む  2.A,B,Cをキーにして数字をハッシュに格納  3.2回目のCまで読み込んだところで1つ前のハッシュと比較  4.AからCの数字がすべて同じだった場合に、現在の行(2つめのCを読み込んでいる)とその前2行を削除(実際にはnextでprintを飛ばす) ところが、4の、さかのぼって行を削除する方法が思いつきません。 なにぶんperlの勉強を始めたばかりで突っ込み所満載のロジックだとは思いますが、解決策をぜひご教示ください。

    • ベストアンサー
    • Perl
  • 空白行の削除マクロについてご教示ください

    空白行の削除に、下記マクロを活用させていただいていますが、 見た目空白なのに削除されない行が時々残ってしまいます。 削除されなかったセルを「Deleteキー」で空白にするとマクロが 実行され、きちんと削除されます。 こういった、スペースか何かが入っていても、見た目空白なら 削除するようにはできないでしょうか。 どなたかよろしくお願いいたします。 Sub 削除() Dim c As Range Dim 開始行 As Long Dim 最終行 As Long 開始行 = 5 最終行 = Range("a5000").End(xlUp).Row For Each c In Range("a" & 開始行 & ":a" & 最終行) If c.Value = "" Then Rows(c.Row).Delete End If Next End Sub

  • perlで配列を複数行削除したいのですが

    @UserDataNum=qw(11 13 34) @PDataLinesの中身 1<>タイトル<>2009/02/10<>適当なデータ<>適当なデータ2<> 2<>タイトル2<>2009/03/13<>適当なデータ<>適当なデータ2<> .. 50<>タイトル3<>2009/03/23<>適当なデータ<>適当なデータ2<> $TODAY=今日の時間; foreach(0..$#PDataLines){ my@aaa= split(/<>/,$PDataLines[$_]); my$a2 = $aaa[2];$a2 =~s{/}{}g; #ここの処理で@UserDataNumに入っている数字と一致する$aaa[0]を含む行を除外し、時間が今日以降のものを配列@Arrayに入れたいのです if(($aaa[0] !~ /@UserDataNum/) && ( $TODAY < $a2)){ push(@Array,$PDataLines[$_]); } } print "\@Array=@Array"; if(grep(!/@UserDataNum/, @PDataLines) && ( $TODAY2 < $a2)){ としてみたり試みているのですが、思うように出来ずにいます。 どなた様かご教授願えませんでしょうか 宜しくお願い致します。

    • ベストアンサー
    • Perl
  • perlについて、教えてください。

    perlについて、教えてください。 「apple.html」と「bigin.html」に、それぞれ, textboxが一つあり、入力値をkeep.cgiで受取り、 「keep.txt」に書込もうと考えています。 a.htmlのテキストボックスに、入力して、submitボタンをクリック しても、「keep.txt」に何も書き込まれません。 「keep.txt」に、 _______ a=100 b=200 ________ のように、書込みたいと考えています。 下記、keep.cgiのどこが間違っているのか、教えてください。 ___以下、「keep.cgi」です。_______________________________ #! c:/perl/bin/perl if($ENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN, $query, $ENV{'CONTENT_LENGTH'}); } else { $query = $ENV{'QUERY_STRING'}; } #$queryに「●_text=●」が入っている。 #ファイルを開く、読み書き用。 $open_file_name = "+<keep.txt"; open(A,$open_file_name); #開いたファイルを、1行ずつ読み込む。 while(<A>){ #$_には、keep.txtの、1行目が入っている。 #$_(読込んだ行)に「●_text」があるか、チェックする if($_ =~ /$query/){ #あった場合 next; } #読込んだ行に、$query以外なら、配列に。 @keep = $_; @keep = $query } #ファイルを閉じる。 close(A); #ファイルを削除する unlink($open_file_name); #削除したのと、同じファイル名で新規作成 $new_file = ">>keep.txt"; open(A,$new_file); #再度、作成したファイルに、配列@keepを書込む。 print A @keep; #ファイルを閉じる close(A); print "Cotent-type:text/html\pirnt n\n"; print <<EOF; <body bgcolor="pink"> <font size="4"> 入力値をファイルに書込みました。<br> </font> EOF exit; ______________________ 宜しくお願いします。

    • ベストアンサー
    • CGI
  • perlで以下の記述の意味についてご助言願いたく。

    while( <$_old> ){ if( $_ =~ /^$var\:(?!\*RK\*)/ ){ print "A\n"; }else{ print "B\n"; } } 上記の上から2行目の if( $_ =~ /^$var\:(?!\*RK\*)/ ){ において、 ()の中の先頭に ?! とあるのですが、 これはどういう解釈なのでしょうか? ご助言ご鞭撻の程宜しくお願い致します。

    • ベストアンサー
    • Perl
  • 重複行を完全削除するエクセルのマクロ

    Sub sakujyo() Dim i, ii As Long For i = 1 To Range("a65336").End(xlUp).Row For ii = Range("a65336").End(xlUp).Row To i + 1 Step -1 If Cells(i, 2).Value = Cells(ii, 2).Value _ And Cells(i, 4).Value = Cells(ii, 4).Value _ And Cells(i, 5).Value = Cells(ii, 5).Value Then Dim iii As Byte iii = 1 Rows(ii).Delete Shift:=xlUp End If Next ii If iii = 1 Then Rows(i).Delete Shift:=xlUp iii = 0 Next i End Sub データーが下の表のように入っております。     A    B    C    E    F 1  1/26  a1234  fdsa  5000  C1 2  1/27  a4567  sdfa  4000  T2 3  1/28  a1234  dfsa  5000  C1 4  1/30  b4567  asdf  6600  A2 5  2/10  b4567  fsda  6600  A2 6  2/10  a1234  afds  5000  C1 B列、E列、F列が完全一致(重複1行目と3行目と6行目・4行目と5行目)で削除し結果的に2行目だけ残る方法がしたいのですが、このマクロですと少ないデータですとうまく動くのですが、『大量のデータを一気に削除出来ない』、『同じ重複が3つ以上のデータが多数ある場合データが削除されずに残ってしまう』エラーが出てしまいます。どうかお教えください。

  • 指定した範囲で0の行を削除するマクロ

    以下のコードで7列目が0の行を削除するマクロを作ったのですが、 13行目以降を削除するように指定できますでしょうか? 1-12行は別のシートに数式を入れているため、削除したくないのですが、 うまくいきません。よろしくお願いいたします。 Sub 行削除() Dim Rw As Long Dim Cnt As Long Application.ScreenUpdating = False For Rw = Cells(Rows.Count, 7).End(xlUp).Row To 1 Step -1 With Cells(Rw, 7) If .Value = 0 Then .EntireRow.Delete Cnt = Cnt + 1 End If End With Next If Cnt = 0 Then MsgBox "削除対象行は、見つかりません。", vbExclamation Else MsgBox Cnt & " 件見つかり行を削除しました。", vbInformation End If End Sub

専門家に質問してみよう