![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
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の中でコントロールできないのかなと思ったりもしましたが
どんな風に考えたらいいのでしょう?
よかったらご指導ください。
No.3ベストアンサー
- 回答日時:
#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;
色々とご指導ありがとうございました。
教えていただいたことをソースに反映させたところ、どうにか自分が思ったとおりの動作をしてくれるようになりました。何しろ、始めたばっかりなのでどういう考え方でやればいいのかそういった部分で経験不足は否めないものか、すごく参考になりました。こういったサイトや皆さんの暖かい助言に感謝します。
また何かすぐお世話になることもあるかと思いますが、ご助言いただけたら幸いです。
No.4
- 回答日時:
データにアクセスするのにキーを用いていて、そのデータが存在するか否かに重きをおくなら、単純なテキスト形式でなく、ハッシュデータベース形式のデータファイルを使ってみては。
こんな感じ: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
ハッシュを使って簡単なデーターベースもできるんですね。今、リファレンス本を見ながらちょっと拝見しましたが、これもじっくり拝見してちょっと試してみたいと思います。参考URLもありがとうございました。
No.2
- 回答日時:
どうせ全行取込、全行書き戻しするのだから、整理整頓しながら処理するように考えれば
わかりやすいと思いますが..
#!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);
未テストです。
お答えありがとうございます。
少し時間がなかったので昨晩御礼をかけなくてごめんなさい。
ソースを見て「あぁ~こんな風な考え方もOKなんだ」と勉強を始めた私としてはとても参考になりました。それぞれの値をハッシュとして取り出してしまうというのもすごいですね。ソースの方を保存したのでもう少し、ソースを見て別パターンのやり方としてやってみます。本当にありがとうございました。
No.1
- 回答日時:
まずフラグを立て($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とともにファイルに書き込む作業もしなければなりませんが、その辺をどうしたらいいのか御教示いただけたらなと思います。初心者の説明ですからわかりにくかったら申し訳ありません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP preg_matchで Warning: Undefined variableが出ます 1 2022/11/15 17:06
- MySQL MYSQL エラー 2 2022/10/18 11:37
- PostgreSQL 画像とカテゴリーを出力したいのですが、取得の条件を付ける方法がわかりません。 2 2022/05/01 18:03
- CGI htmlからパラメータで、cgiに渡したい。 1 2023/02/06 16:15
- JavaScript Javascript初心者|jQueryの.val()で値を取得し複数の要素を連結させる方法知りたい 2 2022/06/02 12:06
- システム ホームページの仕組みについて 3 2022/08/16 14:33
- MySQL 参考書に従って入力したつもりでしたが、最後はエラーがでました。 1 2022/09/28 03:45
- デスクトップパソコン PCの多仕上げ画面の戻し方を教えてください 3 2023/03/08 16:47
- Access(アクセス) DoCmd.SearchForRecord が動かない時の解決方法 3 2022/07/22 15:31
- その他(プログラミング・Web制作) Windowsのマクロプログラムで、こんなことできますか? 3 2022/06/28 14:30
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
MAX関数を使ってからLEFT JOIN...
-
javascriptテキストBOX色を元に...
-
getElementByIdの戻り値がnull...
-
createElementで作成した要素を...
-
読み込んだQRコードをフォーム...
-
console.log結果をhtmlで表示し...
-
iframe内のリンクが飛ばないの...
-
計算結果の表示方法について
-
HTMLタグに複数のクラスを設定...
-
バッチファイルでカウントアッ...
-
「リンクにマウスオーバーする...
-
classList で、class名が付かな...
-
複数のリンク画像を一定時間で...
-
jQueryのアコーディオンメニュ...
-
配列の作業
-
ネストされたハッシュの値から...
-
Notice:Undefined index が。
-
初期表示を変えるには?
-
JavaScript初心者です。URLの末...
-
ボタンを押せば、画面が切り替...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
MAX関数を使ってからLEFT JOIN...
-
javascriptテキストBOX色を元に...
-
読み込んだQRコードをフォーム...
-
createElementで作成した要素を...
-
removeEventListenerについて
-
クリックで色変更後に既に変更...
-
iframe内のリンクが飛ばないの...
-
[急ぎ] videoタグで埋め込んだm...
-
背景色を透明化
-
console.log結果をhtmlで表示し...
-
表示・非表示のスクリプトで、...
-
getElementByIdの戻り値がnull...
-
removeAttribute()メソッドで削...
-
テキストエリア内の一部の文字...
-
タブで開いてさらにタブ内をア...
-
IFRAMEの表示/非表示を切り替え...
-
変数内容をHTML内で表示する方法
-
HTMLタグに複数のクラスを設定...
-
jQueryのアコーディオンメニュ...
-
取得した要素がインライン要素...
おすすめ情報