ログデータの並び替え方法

このQ&Aのポイント
  • ログデータの並び替え方法を詳しく教えてください。
  • 特定の条件でログデータを並び替えるためにはどのような処理が必要ですか?
  • ログデータを並び替えるためには、sort関数を使用する必要があります。詳しい使い方を教えてください。
回答を見る
  • ベストアンサー

ログデーターの並び替え

ログデーターの並び替え 5月1日<>30<>http://com/<>mail@mail 5月5日<>12<>http://com/<>mail@mail 5月7日<>25<>http://com/<>mail@mail 5月10日<>50<>http://com/<>mail@mail 5月23日<>14<>http://com/<>mail@mail 上記のログデータは以下の形式で保存されています。 $date<>$no<>$url<>$mail このログの$noの部分で数値の小さい順、または大きい順に並び替えしたいのですが、 どのようにすればいいのでしょうか? open(IN, "< $logfile"); my $list = <IN>; while(<IN>){ my ($date,$no,$url,$mail) = split(/<>/); if(条件){処理} push(@data, "$_"); } close(IN); #ここで関数 sort を使って並び替えするのだと思うのですが、実際どのようにすればいいかわかりません。 open(OUT,">$logfile"); print OUT $list; print OUT @data; close(OUT); perlは簡単な改造程度しかできなくて、ここのみなさんのように専門的な知識を持っていないので、どうしてもこの並び替えがわからずに困り果てております。お手数ですが、よろしくお願いいたします。

  • Perl
  • 回答数2
  • ありがとう数19

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

  • ベストアンサー
  • kumoz
  • ベストアンサー率64% (120/185)
回答No.2

No が重複する場合は、ハッシュの配列などを使い複数格納する必要があります。 前回のコードを修正したので、試してみてください。 open(IN, "< $logfile") or die "$!"; my $list = <IN>; # ヘッダ行がある? my %data; while (<IN>) { my ($date, $no, $url, $mail) = split(/<>/); push @{$data{$no}}, $_; } close(IN); # $html_data をハッシュに追加 my ($date, $no) = split /<>/, $html_data; push @{$data{$no}}, $html_data; open(OUT,">$logfile") or die "$!"; print OUT $list; print OUT @{$data{$_}} foreach sort { $a <=> $b } keys %data; # 降順 { $b <=> $a } close(OUT); 補足に書かれているコードで並び替えを行う場合は、次のようにするとうまく行くかも知れません。 > ... > if($content=~/<!--mail\/\/-->(.+)<!--mail_end\/\/-->/){$html_data.=$1 . "\n";} > } > push(@data, "$html_data"); > #新たにデーターが追加された@dataの並び順を変更して、以下ログに書き込みを行いたいと思っています。 @data = map { $_->[1] } sort { $a->[0] <=> $b->[0] } map { [(split(/<>/,$_))[1], $_] } @data; > open(OUT,">$logfile"); > ...

TPR_SET
質問者

お礼

ありがとうございます。 おかげさまで並び順の変更ができました。恥ずかしながら、今の自分の知識では、教えていただいたコードを理解できないのですが、今後の為にも理解出来るように精進したいと思います。 自分では到底実装不可能だった機能拡張だったので、本当に助かりました。感謝感激です。

その他の回答 (1)

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.1

No に重複がなければ、No を配列の添字かハッシュのキーに割り当てる方法があります。 以下はハッシュを用いた一例です。 open(IN, "< $logfile") or die "$!"; my $list = <IN>; # ヘッダ行がある? my %data; while (<IN>) { my ($data, $no, $url, $mail) = split(/<>/); $data{$no} = $_; } close(IN); open(OUT,">$logfile") or die "$!"; print OUT $list; print OUT $data{$_} foreach sort { $a <=> $b } keys %data; # 降順 { $b <=> $a } close(OUT);

TPR_SET
質問者

お礼

追記。 補足で提示したソースの処理の順番は、多分、自分の知識では変えようがないように思います。 $logfileを読み込んでから、処理の部分でログの内容と追加内容が重複していないかチェックを行い、 重複していなければ、foreachで複数データーが$html_dataに格納されるようになっています。

TPR_SET
質問者

補足

大変勉強になりました。ありがとうございます。 $noの数値は重複することがあるのですが、重複した行の並び順は特に指定する必要はありません。ただ、重複した行は上書きされてしまったようです。 それと、以下のソースに適用してみようとして試行錯誤してみましたが、何度やってもうまくいきませんでした。かなり複雑なソースのログの並び順を変更する必要があるため、必要な情報をうまく提示できなくて申し訳ございません。 use LWP::Simple; my $content = get($html); open(IN, "< $logfile"); my $list = <IN>; while(<IN>){ my ($date,$no,$url,$mail) = split(/<>/); push(@data, "$_"); } close(IN); if(条件){ if($content=~/<!--data\/\/-->(.+)<!--data_end\/\/-->/){$html_data.=$1 . "<>";} if($content=~/<!--no\/\/-->(.+)<!--no_end\/\/-->/){$html_data.=$1 . "<>";} if($content=~/<!--url\/\/-->(.+)<!--url_end\/\/-->/){$html_data.=$1 . "<>";} if($content=~/<!--mail\/\/-->(.+)<!--mail_end\/\/-->/){$html_data.=$1 . "\n";} } push(@data, "$html_data"); #新たにデーターが追加された@dataの並び順を変更して、以下ログに書き込みを行いたいと思っています。 open(OUT,">$logfile"); print OUT $list; print OUT @data; close(OUT);

関連するQ&A

  • レコードの書込み判断

    ファイルを読込み、読込まれたレコードの39桁目が0であれば出力という判断を下記のコーディングに追加したいのですが、どのように記述すればよいでしょうか? if(open(OUT,">$year$mon$mday$csv")){  for my $fname (sort @dirs){   if(open(IN,"$fname")){   my @lines = <IN>;   print OUT @lines;   close(IN);   }  }  close(OUT); }

  • リクエストの待ち時間が期待通りになりません。

    リクエストの待ち時間が期待通りになりません。 5秒以内にリクエストが行われた場合は、ループとスリープで待たせて、ログに記録されているタイムから5秒以上経過した時点で、新たにログにタイムを記録させたいと思っています。 複数人で同時アクセスもありますので、ループ内で常に最新のファイルを読み込む必要がある?ので、 以下のように書いてみましたが、5秒以内にリクエストした場合、通常は1秒待てば処理が終わるはずなのですが、ループが途中で終わらずに20秒待たされ、$flag==0のまま終わります。 適当な知識しかなくて恥ずかしいですが、どこか間違えている場所があればご指摘くださると幸いです。 my $logfile = "request.dat"; my $time = time; my $i = 0; my $flag=0; while ($i < 20) { $i++; open(IN, "< $logfile"); my ($request_time) = <IN>; close (IN); if($time < $request_time+5) { sleep(1); } else { $flag=1; last; } } if($flag==0){&error;} else { open(OUT,">$logfile"); print OUT $time; close(OUT); }

    • ベストアンサー
    • Perl
  • ログファイルの記録数

    # ログ更新 unshift(@new,"$num<>$addr\n"); open(OUT,">$logfile") || &error("Write Error: $logfile"); print OUT @new; close(OUT); 上記ログの書込みに、最大保存数を設定したいのですが、どのようにすればいいのでしょうか。 $max = 3; とした場合、3行超えたら古いファイルを消したいと考えています。よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • ディレクトリ全てのファイルを読み取るには?

    フリーのCGI掲示板を使ってます。ディレクトリ内に複数のログファイルがあるので、一括して編集・削除ができるように管理部分を改造したいのでアドバイスをお願いします。 一応、readdir関数でディレクトリ内にある全てのファイル名を取得でることは分かりましたが、open関数で全てのファイルを読み取らせる方法がわかりません。 open DIR "./log"; @files = readdir DIR; close DIR; #以下、オリジナルのソースです。 open(IN,"$logfile") || &error("Open Error: $logfile"); while (<IN>) { my ($no,$dat,$nam,$eml,$sub,$com,$url,$hos) = split(/<>/); #途中略 } close(IN);

    • ベストアンサー
    • Perl
  • うまく書き換えが出来ない。

    記事修正画面部分の構築中です。 現在以下のような感じです。 sub edit3 { # ログファイル読み込み open (FILE, "$data") || &error("ファイルが開けません"); @data = <FILE>; close(FILE); # カウント退避 $count = shift (@data); foreach $line (@data) { ($no,$n1,$a1,$com1,$n2,$a2,$com2,$n3,$a3,$com3,$n4,$a4,$com4,$n5,$a5,$com5,$name,$nani,$kou1,$kou2,$pass) = split(/<>/,$line); chomp; if ($in{'edit_no'} eq $no){ $line = "$no<>$in{'n1'}<>$in{'a1'}<>$in{'com1'}<>$in{'n2'}<>$in{'a2'}<>$in{'com2'}<>$in{'n3'}<>$in{'a3'}<>$in{'com3'}<>$in{'n4'}<>$in{'a4'}<>$in{'com4'}<>$in{'n5'}<>$in{'a5'}<>$in{'com5'}<>$in{'name'}<>$in{'nani'}<>$in{'kou1'}<>$in{'kou2'}<>$in{'pass'}<>\n"; } else {$line = "$no<>$n1<>$a1<>$com1<>$n2<>$a2<>$com2<>$n3<>$a3<>$com3<>$n4<>$a4<>$com4<>$n5<>$a5<>$com5<>$name<>$nani<>$kou1<>$kou2<>$pass<>\n";} push(@new,$line); } # ログを更新 unshift(@new,"$count"); open(OUT,">$data") || &error("修正処理を失敗しました"); print OUT @new; close(OUT); &pass; } さて、この状態で複数ある情報の一番最新のものを更新すると、一番古いものまで書き換えられてしまいます。(1.2.3と記事があった場合、3を修正すると、3と1が修正されてしまう) どこがおかしいのでしょうか?自分では間違っているようには見えないのですが… 修正・改善をお願いします。

    • ベストアンサー
    • Perl
  • 複数のCSVを1つのファイルにまとめる

    リモートからダウンロードしたCSVファイルをひとつにまとめる処理をしています。 ダウンロードするリストファイルとCSVファイルのダウンロードはできたのですが、最後にダウンロードしてきたCSVファイルをひとつにまとめるところがうまくいきません。 こちらの過去ログから下記記述してみたのですが、うまくいきません。 if(open(OUT,">$path/$year$mon$mday$csv")){      for my $fname (sort @dirs){        if(open(IN,"$path/$fname")){          my @lines = <IN>;          print OUT @lines;          close(IN);        }     }     close(OUT);   } for my $fname (sort @dirs){の記述で、Unrecognized characterといったエラーが出てうまくいきません。 項目の設定に誤りがあるのでしょうか?perl初心者でよくわかりません。 $fnameや@dirsはどのように設定すればいいのでしょうか?

    • ベストアンサー
    • Perl
  • ロック処理について

    ロック処理について my$id="abc"; open(IN,"file"); while(<IN>){ my ($cid) = split(/\,/); if($cid eq $id){&error;} } close(IN); open(OUT,">>$file"); print "$id,$pass\n"; close(OUT); いままで上記のような書き方でも普通にロック機構を使っていたのですが、 ふと、追加書込みなら必要ないのではと思い至りました。 上記のようにファイルに追加書込みする場合は、ロックは必要ないのでしょうか?

    • ベストアンサー
    • Perl
  • 文字化け対策

    sjisで保存されたファイルを読み込んで、別ファイルに書込みを行ったところ、能等の文字が文字化けを起こしました。 open(IN,"$file"); my $data = <IN>; close(IN); $data=~s/\\//g; open(OUT,">$file2"); print OUT $data; close(OUT); 莫大なソース量だったので、原因を探すのに時間がかかりましたが、一つ一つ消去しながら探したところ、 $data=~s/\\//g; これを消すことで解消しました。 文字化けさせずに\を消すにはどのように書けばいいのでしょうか?

    • ベストアンサー
    • 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);

  • データの入れ替え処理が巧くできないのですが

    いつもお世話になります 簡単なDBを作っているのですが、データの更新処理が巧くいかなくててこずっています POSTメッソドで送られてきた name=actionの内容がedit2、の時 sub menteが実行されます同じく name=noの変数には更新したいファイルの番号がセットされます それらを取得して、ファイルを開き $nooの内容(DBのファイル番号)とnoが一致したらブラウザから送られてきたデータと その部分のデータ($nooはデータの先頭で以降<>で区切って変数が格納される) を入れ替える処理を行いたいのですがどの様に書いたらいいのでしょうか、下記のコードですと変数 $_に更新される前のデータしか代入できず結果ファイルの入れ替えは行えません open(IN,"$logfile") || &error("Open Error : $logfile"); while (<IN>) { ($noo,@arg_[0..$#eqipument],@p[0..5],$n_article,$w_article,@reselect_marks) = split /<>/; if ($no == $noo ) { $_ = join('<>',$noo,(map{$arg_[$_]}(0..$#eqipument)),$p0,$p1,$p2,$p3,$p4,$p5,$n_article,$w_article,@reselect_marks,),'<>',"\n"; } push(@new,$_); } close(IN); # 更新 open(OUT,">$logfile") || &error("Write Error : $logfile"); print OUT @new; close(OUT); 尚ブラウザから送信されてくるデータは以下のような感じです print qq|<form action=\"$myself\" method=\"POST\">\n|; print qq|<input type=hidden name=mode value=\"admin\">\n|; print qq|<input type=hidden name=action value=\"edit2\">\n|; print qq|<input type=hidden name=no value=\"$no\">\n|; 宜しく御教授お願いいたします。

    • ベストアンサー
    • Perl

専門家に質問してみよう