dポイントプレゼントキャンペーン実施中!

perlを勉強し始めて一月足らずのものです。
どう考えてプログラムを組めばいいのかわからなく。
ちょっと困っています。

#!usr/local/bin/perl

$acdata{'id'} = 125;
$acdata{'go'} = 'http://www55.';

if(open(IN,"test5.log")){
@log = <IN>;
close IN;

}else{
$point =1;
$log = join ('<>',$acdata{'id'},$point,$acdata{'go'});
open (OUT,">test5.log");
print OUT "$log\n";
close OUT;
}

foreach (@log){
($id,$point,$url) = split (/<>/,$_);

if ($id == $acdata{'id'}){
$point++;
$log = join ('<>',$acdata{'id'},$point,$acdata{'go'});
open (OUT,">test5.log");
print OUT $log;
}

ログファイルの中のIDナンバーで管理するのですが
ファイル自体がなかったらファイルを作って新規データーを書き込む
IDナンバーと%acdata{'id'}が一致したらポイントを加算して記憶させる。
そこまではできたのですが、すべてのIDとと%acdata{'id'}が
合わなかった場合、データーを追加で書き込むという作業が
なかなか思うように行かず、何度となく書いては消してを繰り返しています。
foreachの中でコントロールできないのかなと思ったりもしましたが
どんな風に考えたらいいのでしょう?
よかったらご指導ください。

A 回答 (4件)

#1です。


一つミスしてました。フラグが変更していなかったら、ログ配列に追加するでした。

#!usr/local/bin/perl

$acdata{'id'} = 11;
$acdata{'go'} = "hhh";

$logfile = "test5.log";
if(-T $logfile){
 #ログファイルがない場合
 @log = ();
}else{
 #ログファイルがある場合
 open(IN,$logfile);
 @log = <IN>;
 close IN;
}
#フラグはループする前に立てる
$flag = 0;
foreach(@log){
 ($id,$point,$url) = split (/<>/,$_);
 if($acdata{'id'} == $id){
  #IDが一致した場合$_(一致したデータ)を書き換え、フラグを変更
  $_ = join('<>',$acdata{'id'},++$point,$acdata{'go'}."\n");
  $flag = 1;
 }
}
if(flag == 0){
 #フラグが変更されていない(一致するデータがない)場合、ログ配列に新規データを追加
 push @log,join('<>',$acdata{'id'},1,$acdata{'go'}."\n");
}
open(LOG,">$logfile");
print LOG @log;
close LOG;
    • good
    • 0
この回答へのお礼

色々とご指導ありがとうございました。
教えていただいたことをソースに反映させたところ、どうにか自分が思ったとおりの動作をしてくれるようになりました。何しろ、始めたばっかりなのでどういう考え方でやればいいのかそういった部分で経験不足は否めないものか、すごく参考になりました。こういったサイトや皆さんの暖かい助言に感謝します。

また何かすぐお世話になることもあるかと思いますが、ご助言いただけたら幸いです。

お礼日時:2005/03/17 13:17

データにアクセスするのにキーを用いていて、そのデータが存在するか否かに重きをおくなら、単純なテキスト形式でなく、ハッシュデータベース形式のデータファイルを使ってみては。

こんな感じ:

dbmopen( %DB, 'acdata', 0644 ) or die;
sub get {
my( $id ) = @_;
my( $point, $go ) = split( $;, $DB{ $id } );
$point = 0 unless $point;
return( 'id', $id, 'point', $point, 'go', $go );
}
sub addpoint {
my( $id, $point, $go ) = @_;
my %a = &get( $id );
$point += $a{'point'};
$DB{ $id } = join( $;, ($point, $go) );
return( 'id', $id, 'point', $point, 'go', $go );
}
sub top10 {
print "Top 10:\n";
my @order;
foreach my $id ( keys %DB ){
my $a = &get( $id );
push @order, [ $id, $a{'point'} ];
}
my $rank = 0;
foreach my $id ( map { $_->[0] } sort { $b->[1] <=> $a->[1] } @order ){
$rank++; last if $rank > 10;
my %a = &get( $id );
print '[', $rank, ']ID=', $id, ',Point=', $a{'point'}, ',Go=', $a{'go'}, "\n";
}
}

%ac = &addpoint( '125', 10, 'http://www55' );
&top10();
%ac = &addpoint( '125', 10, 'http://www55' );
&top10();
%ac = &addpoint( '11', 10, 'http://goo' );
&top10();
%ac = &addpoint( '12', 10, 'http://goo' );
&top10();
%ac = &addpoint( '11', 10, 'http://goo' );
&top10();

dbmclose( %DB );

以下が実行結果:

Top 10:
[1]ID=125,Point=10,Go=http://www55
Top 10:
[1]ID=125,Point=20,Go=http://www55
Top 10:
[1]ID=125,Point=20,Go=http://www55
[2]ID=11,Point=10,Go=http://goo
Top 10:
[1]ID=125,Point=20,Go=http://www55
[2]ID=11,Point=10,Go=http://goo
[3]ID=12,Point=10,Go=http://goo
Top 10:
[1]ID=125,Point=20,Go=http://www55
[2]ID=11,Point=20,Go=http://goo
[3]ID=12,Point=10,Go=http://goo

参考URL:http://perlmonks.thepen.com/perlfunc:dbmopen.html
    • good
    • 0
この回答へのお礼

ハッシュを使って簡単なデーターベースもできるんですね。今、リファレンス本を見ながらちょっと拝見しましたが、これもじっくり拝見してちょっと試してみたいと思います。参考URLもありがとうございました。

お礼日時:2005/03/17 13:36

どうせ全行取込、全行書き戻しするのだから、整理整頓しながら処理するように考えれば


わかりやすいと思いますが..

#!usr/local/bin/perl

$acdata{'id'} = 125;
$acdata{'go'} = 'http://www55.';

#取込
open(IN,"test5.log");
while(<IN>)
{
@l=split(/<>/,3);
$POINT{$l[0]}=$l[1];
$URL{$l[0]}=$l[1];
}
close(IN);

#加算
if($POINT{$acdata{'id'}} eq "")
{
#無いじゃん
$POINT{$acdata{'id'}}=1;
$URL{$acdata{'id'}}=$acdata{'go'};
}
else
{
#あった
$POINT{$acdata{'id'}}++;
}

#書き戻し
open(OUT,"test5.log");
for(sort(keys(%POINT))
{
print OUT $_,'<>',$POINT{$_},'<>',$URL{$_},"\n";
}
close(OUT);

未テストです。
    • good
    • 0
この回答へのお礼

お答えありがとうございます。
少し時間がなかったので昨晩御礼をかけなくてごめんなさい。
ソースを見て「あぁ~こんな風な考え方もOKなんだ」と勉強を始めた私としてはとても参考になりました。それぞれの値をハッシュとして取り出してしまうというのもすごいですね。ソースの方を保存したのでもう少し、ソースを見て別パターンのやり方としてやってみます。本当にありがとうございました。

お礼日時:2005/03/17 13:29

まずフラグを立て($flag = 0)、foreach内でデータの一致するものがあればフラグを変更($flag = 1)する。

(一致するデータがあればそのデータも変更)
ループ終了後、フラグが変更していればログ配列に追加し、その後ファイルに書き出す。
以上の様な方法はどうでしょう?


$flag = 0;
foreach $log(@log){
 ($id,$point,$url) = split(/<>/,$_);
 if($id == $acdata{'id'}){
  $log = join('<>',$acdata{'id'},++$point,$acdata{'go'});
  flag = 1;
 }
}
if(flag == 1){
 push @log,join('<>',$acdata{'id'},'0',$acdata{'go'});
}
open(LOG,">log.txt");
foreach(@log){
 print LOG "$_\n";
}
close LOG;

この回答への補足

早速ありがとうございました。
こういうことかなぁ~ということで自分のソースに組み込んで見ました。

#!usr/local/bin/perl

$acdata{'id'} = 11;
$acdata{'go'} = "hhh";

if (open (IN,"test.log")){
@log = <IN>;
chomp(@log);
close IN;
}

else{
open (OUT,">test.log");
$point = 1;
$log = join ('<>',$acdata{'id'},$point, $acdata{'go'});
print OUT "$log\n";
}

foreach (@log){
($id,$point,$jumpurl) = split(/<>/,$_);
$flog = 0;
if ( $id == $acdata{'id'}){
$point++;
$flog = 1;
}
}
if ($flog == 1){
push @log, join ('<>',$acdata{'id'},$point,$acdata{'go'});
}

open (OUT,">>test.log");

foreach(@log){
print OUT "$_\n";
}

close OUT;


exit;

しかし、一番肝心な部分がうまく作動しないようです。
ファイルログに記録してあるIDと取り込んだIDが一緒の場合、そのままポイントの数値をインクリメントした形で再度記録をするような形にしたいのですが、ポイントがインクリメントされていないログとインクリメントされたログの両方がファイルに記録されてしまうようです。

私の説明が下手なのでご理解していただけるかわからないのですが、入力されたIDとログのIDが一致した場合、IDが一致した配列を消去してポイントをインクリメントした同じIDの配列を差し替えたいということなんですが、foreachの処理の中で何度か色々考えてやってみたのですが、僕のか考えていることは無理な話なのかなと自信がなくなったので皆さんにお聞きしたいと思って質問しました。

また、配列の中に合致するIDがなかった場合新たに取得したIDナンバーにポイント1をセットしてURLとともにファイルに書き込む作業もしなければなりませんが、その辺をどうしたらいいのか御教示いただけたらなと思います。初心者の説明ですからわかりにくかったら申し訳ありません。

補足日時:2005/03/16 23:54
    • good
    • 0

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