Perlでファイルのデータの一部を削除する方法とは?

このQ&Aのポイント
  • 久しぶりにPerlを操作してファイルのデータの一部を削除したいのですが、うまくできません。
  • 具体的には、「めがね」というデータを削除したいのですが、正しい動作が確認できません。
  • 指導をお願いします。
回答を見る
  • ベストアンサー

perlでファイルのデータの一部を削除したい

久しぶりにPerlを操作してファイルのデータの一部を削除したいのですが、削除出来ずに困っております。 3年以上触っていないため、過去のファイル等々を見ながらやってましたが、結果は出来ずじまいで停滞して困っております。 ご指導いただけないかと思い、書き込みしました。 ファイル名 $tmpfile データ構成  no,名称 1<>フレーム 2<>レンズ 3<>カメラ 4<>ファインダー 5<>めがね 6<>ズーム これで「めがね」を削除したいのです。 データnoで削除したいと思っておりますが、うまく動作しません。 以下ソース open(DB,"$tmpfile") || &error("Open Error : $tmpfile"); flock(DB, 1); @lines = <DB>; @new=(); foreach $line (@lines) { $flag=0; ($no,$meisyo) = split("<>", $line); foreach $x (@DEL) { if ("$x" eq $tmpnum) { $flag=1; last; } } if ($flag == 0) { push(@new,$line); } } open(OUT,">$tmpfile") || &error("Write Error : $tmpfile"); print OUT @new; close(OUT); ここまで 上のソースですと、エラーこそならずに(そうみえているだけかもしれません)終わりますが、データ削除が正しく出来ませんでした。 説明不足があるかもしれませんので、指摘いただけますと幸いです。 よろしくお願いいたします。

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

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

  • ベストアンサー
  • Gotthold
  • ベストアンサー率47% (396/832)
回答No.1

ファイルを書き換えたいのであれば、 読み書き両用モードでオープンしてください。 そうしないと排他制御もうまくできません。 (読み込みモードopen→close→書き出しモードopen→closeでもできますが、排他制御が不完全になります。) 以下サンプル。 ============================================== use utf8; #ソースコードはUTF-8で記述 use strict; #厳しい文法チェック # ファイルオープン、文字コードUTF-8 # ファイルの文字コードがUTF-8以外の時は open(my $fp, "+<:encoding(cp932)", "data.txt" ) の様に指定 my $st = open(my $fp, "+<:utf8", "data.txt" ) or die "File open error"; flock($fp, 2); # 読み込み my @data = <$fp> ; # 編集 @data = grep { my @temp = split("<>"); $temp[0] ne "5" } @data; # 書き出し seek($fp, 0, 0); #書き込む場所をファイルの先頭に truncate($fp, 0); #ファイルサイズを0byteに print $fp @data; close($fp); ============================================== 2引数openや、ベアワードをファイルハンドルに使う書き方は ものすごく古い書き方なので、 上記サンプルでは使っていません。 なお、提示のソースですが、 @DELや$tmpnumが説明無しに出現しているのが気になります。 特に$tmpnumほうは記述ミスでは?

hihin2003
質問者

お礼

回答ありがとうございます。 >特に$tmpnumほうは記述ミスでは? 申し訳ございません。その通りでした。 サンプルにならって修正いたしましたら、無事削除出来ました。 ありがとうございます。 プログラムの記述についても勉強になります。 本当に助かりました。

関連するQ&A

  • データ件数が多くなってもエラーにならない方法

    perlで、URLからサイトが表示されるかを確認するプログラムを作成しました。 ただ現在の方法だと、チェックするデータ件数が多くなるとエラーとなってしまいます。 現在のソース (ここから) open(DB,"$memfile") || &error("Open Error : $memfile"); flock DB, 2; @lines = <DB>; close(DB); @new=(); foreach $line (@lines) { $flag=0; ($num,$url,$title) = split("<>", $line); &url_ckeck("$url"); $data = "$num<>$url<>$title\n"; $data =~ s/\n<>/<>/g; $data =~ s/\r\n<>/<>/g; $data =~ s/\r<>/<>/g; push(@new,$data); } open OUT, "> $memfile"; print OUT @new; close OUT; (ここまで) この方法だと300件を超えると「ページが表示出来ない」エラーがでてしまうので、 チェックの方法を小分けしてエラー回避できないかを考えているのですが、とのようにすれば良いのかがわからず先に進められなくなってしまいました。 プログラムも見よう見真似で作成しているのでおかしな箇所が多々あるかと思いますが、助けていただけないかと思い書き込みました。 「$line (@lines)」を「$start .. $end」として件数を小分けにしてボタンを表示させてクリックして進められるようにしてみたらとも思いましたが データがうまく更新出来ずにいます。 不明点はご指摘ください。 よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • 2つのデータを統合を効率よく出来ません

    2つのデータを統合を効率よく出来ません 2つのデータを統合するプログラムをperlで作成しています。 データはテキストでサーバー環境にあります。 クラスデータ 1,1-1,1年 2,1-2,1年 3,1-3,1年 4,2-1,2年 5,2-2,2年 6,3-1,3年 7,3-2,3年 名前データ 1,田中,たなか 2,伊藤,いとう 3,斎藤,さいとう 4,上野,うえの 5,大阪,おおさか 6,福島,ふくしま 7,矢部,やべ 最終データ 1,田中,たなか,1-1,1年 2,伊藤,いとう,1-2,1年 3,斎藤,さいとう,1-3,1年 4,上野,うえの,2-1,2年 5,大阪,おおさか,2-2,2年 6,福島,ふくしま,3-1,3年 7,矢部,やべ,3-2,3年 以下のプログラムで動作させていますが、件数が多くなると非常に非効率となり動作しなくなります。 ※公開用にプログラムを修正しています。おかしい部分があるかもしれません。 (ここから) 略・・・ open(DB10,"<$namefile") || next; flock(DB10, 1); @lines10 = <DB10>; close(DB10); foreach $lines10 (@lines10) { ($seq,$name,$kana,$classnew,$nennew) = split("<>", $lines10); open(DATA,"$classfile")|| die &error(" $classfile を読み込みopen出来ません"); flock(DATA,1); @lines11 = <DATA>; close(DATA); foreach $lines11(@lines11){ ($seq1,$class,$nen) = split("<>", $lines11); $classnew = $class; $nennew = $nen; open(DATA1,"$classfile")|| die &error(" $classfile を読み込みopen出来ません"); flock(DATA1,1); @line21 = <DATA1>; close(DATA1); foreach $line21(@line21){ local(@val) = split("<>", $line21); if($seq1 == $val[0]){ $line21 ="";} push(@new,"$line21"); } push(@new,"$seq1<>$class<>$nen\n"); open(DATA1,">$classfile")|| die &error(" $classfile をwrite出来ません "); flock(DATA1,2); print DATA1 @new; close(DATA1); @new = ""; } @new1 = ""; open(DB12,"<$namefile") || &error("Can't open $namefile"); flock(DB12, 1); @line12 = <DB12>; close(DB12); foreach $line12 (@line12) { local(@val1) = split("<>", $line12); if($seq == "$val1[0]"){ $line12 ="";} push(@new1,"$line12"); } push(@new1,"$seq<>$name<>$kana<>$classnew<>$nennew<>\n"); open(DB12,">$namefile")|| die &error(" $namefile をwrite出来ません "); flock(DB12,2); print DB12 @new1; close(DB12); } } (ここまで) プログラムの流れとしては(私が解釈している)、2つのファイルを1件読み込み更新を最終行へ毎回行っているというものになります。 恐らく、もっと効率の良い方法があるとは思っているのですが、アイデアが浮かばす止まってしまいました。 このプログラムではなく別のものでもOKです。私がこの方法しかしらないのでこの記述をしています。 ファイルの更新系でアドバイスがいただけたらと思い書き込みます。 ご指導よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • CSVデータの編集の際の重複チェックの方法

    今、data.csv(カンマ区切り)として、左から順位、名前、性別という3項目で、10人程度のリストデータがあります。 data.csv(カンマ区切り)を編集するようにしていますが、順位は重複してはならないので、重複していたらエラーを出したいのですが。。。 ($rank,$name,$sex) = split(/\,/,$line); です。 open(IN,"$logfile") || &error("ファイルが開けません"); @lines = <IN>; close(IN); # 情報の書換え foreach $line (@lines) { ($rank,$name,$sex) = split(/\,/,$line); $line = "$in{'rank'},$name,$sex\n";} push(@new,$line); } # ファイルを更新 open(OUT,">$logfile") || &error("ファイルが開けません"); print OUT @new; close(OUT);

  • データ削除方法について

    現在以下のプログラムでデータを削除しています。 (ここから) print "Content-type: text/html\n\n"; open(IN,"<$memfile") || &error("Can't write $memfile"); flock(IN, 2); @lines = <IN>; foreach $lines (@lines) { ($seq,$name) = split("<>", $lines); if("$del" eq "$seq"){ next; }else{ $data .= $lines; } } close IN; open OUT, "> $memfile"; flock OUT, 2; print OUT $data; close OUT; print "<html>完了しました<br><a href=?mode=menu>戻る</a></body></html>"; exit; (ここまで) このプログラムでも削除出来るのですが、foreachの処理で対応するとパフォーマンスが悪いのかな? と思ってます。(ハッキリとはわかりません) 件数が多くなるとサーバーエラーになるのかな?と思ってます。 もっと効率の良い方法がありましたらと思い質問いたしました。 perlを独学で学んでいるので、見る人が見ると変なつくりだと思ってます。 以上、よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • perlで容量の大きいCSVファイルを開く方法

    perlで容量の大きいCSVファイルを開く方法 ファイル容量の大きいcsvファイルから、必要な項目を抜き出して別ファイルにするプログラムを作成したいと思ってます。 csvファイルが少ない場合は動作したのですが、容量が140MBを超えたデータを読み込もうとすると、ブラウザー表示で何も変化いたしません プログラムは以下のようになってます。 ------------------------------------------------- 略 open(IN,"$inport") || &error(" $inport を読み込みopen出来ません"); flock(IN,1); @lines = <IN>; foreach $lines (@lines) { local(@val) = split("\,", $lines); print "$val[0]"; $dat .= "$val[1]\,$val[5]\n"; } open(OUT,">$dcsv"); flock(OUT,2); print OUT "$dat"; close OUT; 略 ------------------------------------------------- 件数も多いので、foreachを$lines (@lines) としないで($start .. $end)として読み込みの件数を制限して対応しようと考えてましたが、うまくいきませんでした。 ご指導いただけますと幸いです。

    • ベストアンサー
    • Perl
  • ファイルを読み込み、URL転送をしたい

    URL転送するプログラムを作成してます。 以下のURLでアクセスします。 http://hoge.com/index.cgi?mou=1 以下のデータ構成となってます。 dat.cgiのデータ 1<>http://google.co.jp/ 2<>http://yahoo.co.jp/ 3<>http://goo.ne.jp/ 4<>http://msn.co.jp/ この場合1レコード目のURLを転送しgoogleのサイトを表示させたいのですが、初歩的なミスでサーバーエラー 500を表示しています。 index.cgi (ここから) #!/usr/bin/perl # 文字コード取得 require './jcode.pl'; $datfile = "./dat.cgi"; open(DB,"$datfile") || &error("Open Error : $datfile"); @lines = <DB>; close(DB); @new=(); foreach $line (@lines) { $flag=0; ($num,$mourl) = split("<>", $line); foreach $mou (@DEL) { if ($mou eq "$num") { print "Location: $mourl"; } } } (ここまで) 同じホルダーに jcode.pl dat.cgi は入っています。 申し訳ありません。よろしくご指導をお願いいたします。

  • データファイルのソート方法について

    perlで使用している、データファイルのソート方法について質問いたします。 やりたいこと。 1.ファイルを読み込み 2.指定されている文字列でソートをして 3.同じファイルに格納する 以上になります。 以下のファイルにデーターが入ってます・ namedata.cgi 田中,4 佐藤,2 鈴木,1 水野,3 このファイルをソートして以下のように並び替えて保存したいと思ってます。 スクリプトを実行後 namedata.cgi 鈴木,1 佐藤,2 水野,3 田中,4 となっていてほしいのです。 スクリプト sort.cgi 略・・・ #ふぁいる読み込み open(DB,"<$file") || &error("Can't write $file"); flock(DB, 1); @lines = <DB>; close(DB); #ソート @result = sort { $a <=> $b } @lines; #ファイル書き込み open(DB,">$file") || &error("Can't write $file"); flock(DB, 2); print DB "@result"; close(DB); ファイルの2項目目が分からないからソートされていないような気がするのですが、記述方法がわかりません。 ファイル読み込み時にforeachを使用して読み込まないとだけなのでしょうか? うまく説明できていないかもしれませんが、よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • 要素を削除する最適な方法

    たいへん困っています。Perlでプログラムを作成しており配列要素の削除を行なおうとしています。 例えば下のようなデーターをdata.txtファイルに保存しているとしてください。 1,洋服,婦人服,子供服,男性服, 2,時計, 3,アクセサリ, 上のデーターで1行目にある子供服を削除して 1,洋服,婦人服,男性服, 2,時計, 3,アクセサリ, のようにずらしたいのです。 私がとった方法はデーターをopenで開きforeachで行をまず呼びこみます。 if(!open(DATA,"$data")){&error('ファイル読み取りエラー。'); } else{ @data=<DATA>; close(DATA); } foreach $line (@data){ chomp $line; ($no,@sub)=split(/,/,$line); if($no eq 1){ $i=-1; foreach (@sub){$i++; if($sub[$i] eq '子供服'){next;} else{push @newsub,"$sub[$i]";next; } } push @newline,"$no,@newsub\n";} else{push @newcline,"$line\n";} } これで@newlineを表示すると 1,洋服,婦人服, 男性服, 2,時計, 3,アクセサリ, のように男性の前の部分が半角空白として保存されます。 どうしてなのでしょうか?そもそもこういったやり方が間違っているのか、それとも一部だけまちがっているのかもわかりません。お手数ですがどなたか教えてください。

    • ベストアンサー
    • Perl
  • perl初心者です。宜しくお願い致します。

    ファイルの容量が大きく。perlを使用してデータの集計をしています。 "A"がきたらflag1をたてなさい。 "B"がきたらflag2をたてなさい。 "C"がきたらflag3をたてなさい。 これでAとBとCを抜き取ること&AからCまでの時間を取得したのですが、 Bの数のmaxの値だけを抜き取りたいのですが、Bがきたときの数をすべて 出力してしまいます。下記の文だと、Bが4回きたら、1,2,3,4と出力してしまいます。 それで4だけを出力したいのですがどのように書き換えたらようか教えて頂けますでしょうか。 '----------------------------------------------------------------------------- open (IN,"< $ARGV[0].txt") or die; open (OUT,"> $ARGV[0]_out.txt") or die; $flag =0; my $a, $b, $c; $count = 0; ####################################################### while($line =<IN>){ ($time,$data) = split(/\s+/,$line); if($data eq "A") { $flag=1; $a = $time; #print OUT $line; #print OUT "\n"; } elsif($data eq "B"){ $flag=2; $count++; $count == $data; print OUT ("$count\n") } #print OUT ("$count\n"); elsif($data eq "C"){ $flag=0; $count=0; $b = $time; $c = $b - $a; print OUT ("time $c\n") } } -------------------------------------------------------------------------------

  • Perlでファイルを読み込みタグを削除する方法

    以下のようなソースを書きました。 HTMLファイルを読み込み、タグを全て削除して他のファイルに書き込むソースです。 しかし、上手く動作しません。 問題点を教えていただけませんでしょうか。 お願いします。 #!/usr/local/bin/perl package www3sub2; sub main(){ open(FH, "<googlefile3_.txt"); my @file = <FH>; close(FH); open(OUTB,"> googlefile6.txt"); foreach(@file){ my $line = $_; $line =~ s/<("[^"]*"|'[^']*'|[^'">])*>//g; print OUTB "$line"; close(OUTB); } } 1;

専門家に質問してみよう