Perlコーディング初心者質問スレ Part 43
■ このスレッドは過去ログ倉庫に格納されています
0001nobodyさん
2005/08/12(金) 01:26:47ID:mHnZWvqz【投稿する際の注意】
質問するときは内容をよく吟味してから投稿してください。
「コマンドの意味がわかんない」とかはマニュアル見ましょう。
回答者さんは何でも屋じゃありません。
1: 自分はこういう事がしたい。
2: それでこんな風にやってみたが・・・
3: こんなエラーが出て上手く行かなかった。
最低でも1と3が無いと誰も答えられないよ。
ソース貼る時は、全角スペースでインデント忘れずに。
良い回答は良い質問から。一緒に勉強しましょう。
過去ログやお勧めサイトは >>2-10
0097nobodyさん
2005/08/22(月) 23:01:26ID:???全然追ってないけど、とりあえず $in{'mons'} と $in{'timeh'} は
ループの外へ出して別変数に入れようよ。
0098nobodyさん
2005/08/22(月) 23:19:39ID:???$sizeという数値が入る変数があり、これをヒアドキュメントで出力したいのですが、
print <<"EOF";
log file size $sizeKB
EOF
などと書くと、$sizeとKBではなく$sizeKBという変数として認識されてしまうのですが、
ヒアドキュメンド内で変数の直後に半角英数字を続けて書く方法はないでしょうか。
0101nobodyさん
2005/08/23(火) 00:16:13ID:???いいんじゃない?
私は頭の部分をこう書くかな。
my @tempmons = qw{dummy 城内2時間キングアッピー 城内10時間キングアッピー ...};
my %mons_to_index;
@mons_to_index{@tempmons} = 0..$#tempmons;
0102nobodyさん
2005/08/23(火) 00:49:00ID:???んじゃ、その %mons_to_indexがもう出来てるとして俺は空間効率でも上げてみるか。
頭の中で考えただけだから、間違ってたらごめん。
my $tm = $in{'timeh'};
my $mons_id = $mons_to_index{$in{'mons'}};
foreach my $hour (@hourlist) {
my $i = 0;
while ($hour =~ m/<>/go) {
next if $i++ != $mons_id;
$hour =~ s/[^<>]+<>\G/$tm<>/o;
last;
}
}
ところで、なんで @hourlist が配列なのか不明。
もとのコード >>92 でも foreach で回してるけど、$mons* が上書きされちゃうし。
0103nobodyさん
2005/08/23(火) 01:26:51ID:???sub data_load {
open DATA, "<data.txt" or die "Can't open : $@";
my @lines = <DATA>;
close DATA;
return [ undef, map{ split '<>' } @lines ];
}
sub data_save {
my @data = join '<>' => map{ $$_ } @_;
local $" = "\n";
open DATA, ">>data.txt" or die "Can't open : $@";
print DATA "@data";
close DATA;
}
とすれば
@::ref_hours = data_load();
$::ref_hours->[ $in{mons} ] = $in{timeh};
data_save( @::ref_hours );
応用方法もいくらでもあるだろう。
0104nobodyさん
2005/08/23(火) 01:32:14ID:???return map{ [ undef, split/<>/,$_ ] } @lines;
だな。
my @tempmons = qw{ 城内2時間キングアッピー 城内10時間キングアッピー ...};
my %mons_to_index;
@mons_to_index{@tempmons} = 0..$#tempmons;
にして
return map{ split/<>/ } @lines;
とかしたいが元スクリプト読む気ないので間違ってるかも。
0105nobodyさん
2005/08/23(火) 01:35:17ID:???X return map{ split/<>/ } @lines;
O return map{ [split/<>/] } @lines;
0106nobodyさん
2005/08/23(火) 02:18:30ID:???0107nobodyさん
2005/08/23(火) 02:21:03ID:???0108nobodyさん
2005/08/23(火) 02:22:58ID:???うは、正規表現を使いますか。
(foreachは遅いとかの突っ込みは無しの方向で)
my $tm = $in{timeh};
my $mons_id = $mons_to_index{$in{mons}} || @tempmons;
foreach my $hour (@hourlist){
foreach(1..$mons_id){
$hour =~ m/<>/g;
}
$hour =~ s/\G[^<>]+/$tm/;
}
0109nobodyさん
2005/08/23(火) 09:47:32ID:???>>102 です。
どうも元のコード読む限り、置換は一ヶ所だけなんだよね。elsif で繋いであるし。
正規表現の作製コストと、splitかけてjoinするコスト
どっちが良いかは、この場合かなり微妙…。もしかしたらsplit, joinのが安いかも。
0110nobodyさん
2005/08/23(火) 12:04:31ID:???最近見かけた名言を贈ろう。
「推測するな。計測しろ」
http://search.cpan.org/~nwclark/perl-5.8.7/lib/Benchmark.pm
0111nobodyさん
2005/08/23(火) 12:40:05ID:???0112nobodyさん
2005/08/23(火) 13:46:44ID:???my @moge = (1, 2, 3, 4);
my @foo = (\@hoge, \@moge);
@fooを使って、$hoge[2]の値を取得するにはどうすればよいですか?
\@hogeは必ず$foo[0]にあります。
0113nobodyさん
2005/08/23(火) 13:57:40ID:???http://perldoc.jp/docs/perl/5.6.1/perllol.pod
http://www.kt.rim.or.jp/~kbk/perl-5.8/perlreftut.html
http://www.kt.rim.or.jp/%7Ekbk/perl5.005/perlref.html
0114108
2005/08/23(火) 14:42:04ID:???一回だったら微妙かもですね。
>>110
ベンチなら正規表現の方が2倍速かった。(@hourlist=10で計測)
ただ、ベンチは繰り返し実行するから、
正規表現のコンパイルコストなど測れない部分がある。
大抵は無視できるけど、一回こっきりの話だと無視できない可能性も。
細かい話だけどね。
0115102
2005/08/23(火) 17:55:10ID:???ありがとう。その通りです。
ベンチ鬼のようにやってたから、目測でコスト見積るようになった。
「スカラ変数宣言で◯バイト消費。数値入力でヘッダ部分にビットが立つ。ボディーが追加されて数値設定。文字列として使っちゃったから、ヘッダ部のビット変更。ボディーの数値構造体切り離して、両用の構造体に変更。」
とか、気にしてた頃はスクリプト見ながらここまで考えてた(あほです)。
>>114
わざわざベンチありがとう。やっぱり1回だと微妙ですよね…。m/<>/go がリニアサーチだし。
0116nobodyさん
2005/08/23(火) 21:09:27ID:???そこら中のサイトで「セキュリティーホールだ!クリップボードの内容が盗見られる!」
と騒ぎ立ててんだけど、もちろんsubmit送信を使えば値を渡すことができるだろうけど、
1回の閲覧のみでJavaScriptで取った値をCGIに渡すことは不可能だよね?
0117nobodyさん
2005/08/23(火) 21:14:43ID:???太郎,男,20才
花子,女,21才
健太,男,22才
・
・
というデータがname.datというファイルでcgiと同じディレクトリにあり、
パラメータとして'健太'を与えてやると、'22才'と返ってくるようなスクリプトは、どう書けばいいのでしょうか。
よろしくお願いします。
0118nobodyさん
2005/08/23(火) 21:22:48ID:???while (<IN>) {
chomp;
my @tmp = split /,/;
$name2age{$tmp[0]} = $tmp[2];
}
close IN;
print $name2age{'健太'};
ハッシュのキーに漢字ってキモいな
0119nobodyさん
2005/08/23(火) 21:28:56ID:???みたいなハッシュを別に作って解決
(゚∀。)アリャ?
0123nobodyさん
2005/08/24(水) 01:11:31ID:???0124nobodyさん
2005/08/24(水) 01:11:32ID:???いずれにせよバレバレっぽいなぁ
0126nobodyさん
2005/08/24(水) 01:16:54ID:???0127nobodyさん
2005/08/24(水) 04:39:31ID:???板違い。
http://pc8.2ch.net/test/read.cgi/sec/1005185421/
0128nobodyさん
2005/08/24(水) 05:33:37ID:???PCからは書き込みができるのですが携帯(�@モード)からは書き込みはおろか管理画面へすら入れません。
CGI本体のソースはこちらになります。
http://namihei.zone.ne.jp/upup/up/44694.txt
他にはlogファイルとjcode.plを使います。
enctype="multipart/form-data"あたりに問題があるように思うのですが行き詰まってしまいました。
どこをどのようにすれば携帯から書き込めるようになるでしょうか?
0129128
2005/08/24(水) 05:37:30ID:???ttp://namihei.zone.ne.jp/upup/up/44694.txt
0130nobodyさん
2005/08/24(水) 06:19:55ID:???原因わかってるならenctype="multipart/form-data"を消せばいいやん
それはファイル添付するときのenctypeだし
どうしてもenctype書きたいならenctype="x-www-form-urlencoded"で
0133nobodyさん
2005/08/24(水) 08:47:43ID:???0134nobodyさん
2005/08/24(水) 09:45:36ID:???ファイルを開いて読んで配列に入れてから書き込むを永遠と繰り返すしかないんでしょうか。
0136nobodyさん
2005/08/24(水) 11:04:23ID:ephPxiIZ0137nobodyさん
2005/08/24(水) 11:15:53ID:???他の方法お願いします。
0138nobodyさん
2005/08/24(水) 11:24:30ID:???ファイルを開いて書き込むのを繰り返すのが普通。ただし
配列に入れるのは無駄なので読んだらどんどん書き出せ。
.
0141nobodyさん
2005/08/24(水) 15:15:16ID:???パラメータ$goodsnumに入れた商品番号$tmp[0]に対する得票数$tmp[1]を
カウントアップさせたいのですが、ログファイルがうまく更新されません。
コードは以下の通りです。
open(LOG, "+<$file");
flock(LOG,2);
print "Content-type: text/html\n\n";
while ($line = <LOG>) {
@tmp = split /,/,"$line";
if ("$tmp[0]" eq "$goodsnum"){
seek(IN,0,0);
$tmp[1] ++;
print LOG "$tmp[0],$tmp[1]\n";
truncate(IN,tell());
print "商品番号$tmp[0]の得票数は$tmp[1]";
}
}
flock(LOG,8);
close(LOG);
期待する結果(ログファイルの内容)
実行前 syohin555,0 → 実行後 syohin555,1
実際の結果(ログファイルの内容)
実行前 syohin555,0 → 実行後 syohin555,0[改行]syohin555.1
ログファイルには他にも商品の投票データがあり、パラメータで渡した商品のみ、カウントアップさせる企てです。
ごちゃごちゃして申し訳ありません。どうぞよろしくお願いします。
0144nobodyさん
2005/08/24(水) 15:56:30ID:???一行の長さが不定なテキストデータを、読み出しながら書き出すのは無茶。
得票数が 9 => 10 になったらまずいよね。
全部読み込んでから全部書き出すのが無難じゃないかな。
0146nobodyさん
2005/08/24(水) 16:10:26ID:???chomp;がないのに¥nつけると改行だけ増える罠。
根本的に流れがおかしい希ガス。
0147141
2005/08/24(水) 16:15:29ID:???なんとか頑張ってみます(; ;)
0148141
2005/08/24(水) 17:33:40ID:???大まかな構想を練っているのですが、アドバイス頂けますでしょうか。
1.ログファイルを開く
2.改行で切り分けて@ary1にいれる
3.$ary1[0],[1],[2]...をそれぞれカンマで切り分けて@ary2に入れる
4.whileを使って$ary2[0]がパラメータに合致するノードを探す
5.見つかったら$ary2[1]をカウントアップ。
6.@ary1をログファイルに上書きする
こんな感じでしょうか?
頭が爆発しそうなのでよろしくお願いします。
0149nobodyさん
2005/08/24(水) 17:43:24ID:???大まかな流れはそんな感じで良いと思う。
あと、得票数のデータは配列にするんじゃなくてハッシュにするとやりやすいと思う。
0151nobodyさん
2005/08/24(水) 18:00:22ID:???・foreachかwhileで一行ずつ読み込む
・カンマで区切り、それぞれを変数で区切る
・最初の要素とパラメタが一致すれば、最後の要素をインクリメント
・3つの変数をカンマ区切りで配列に
・処理終了後、配列をログファイルに上書き
じゃだめなのか
0152nobodyさん
2005/08/24(水) 18:02:50ID:???open(LOG, "+<$file");
print "Content-type: text/html\n\n";
while (<LOG>) {
chomp;
@tmp = split /,/;
if ($tmp[0] eq $goodsnum){ $tmp[1] ++; }
push(@txt, "$tmp[0],$tmp[1]\n");
print "商品番号$tmp[0]の得票数は$tmp[1]";
}
seek(LOG, 0, 0);
print LOG @txt;
truncate (LOG, tell(LOG));
close(LOG);
ファイルの内容を丸まる配列に入れちゃうのは初心者の処理だけど、まぁ後は理解して改造してくれ。
0153141
2005/08/24(水) 18:13:54ID:???もう丸一日かまってるから混乱してきた。
最終的なコードはこうなりました。
みんなありがとう!
@ary = ();
open(LOG, "+<$file");
flock(LOG,2);
print "Content-type: text/html\n\n";
while ($line = <LOG>) {
chomp($line);
@tmp = split /,/,"$line";
if ("$tmp[0]" eq "$goodsnum"){
$tmp[1] ++;
push(@ary,"$tmp[0],$tmp[1]\n");
}else{
push(@ary,"$tmp[0],$tmp[1]\n");
}
}
seek(LOG, 0, 0);
print LOG @ary;
truncate (LOG, tell(LOG));
flock(LOG,8);
close(LOG);
>>151
>>152
ありがとうございます。
今から確認してみます。
0154nobodyさん
2005/08/24(水) 19:59:02ID:???例えば、こんな感じで。
$opt = "or";
print "OR : OK" if(1 == 1 $opt 2 == 1);
$opt = "and";
print "AND : OK" if(1 == 1 $opt 2 == 1);
[表示結果]
OR : OK
0155nobodyさん
2005/08/24(水) 20:02:21ID:???0156154
2005/08/24(水) 20:09:36ID:???$opt = "or";
print "OR : OK" if(1 == 1 eval($opt) 2 == 1);
としても、
$opt = "or";
print "OR : OK" eval(if(1 == 1 $opt 2 == 1));
としても、正常に動かないのですが・・・
evalつけるところ間違えてます・・・?
0157nobodyさん
2005/08/24(水) 20:23:46ID:???$opt = "or";
eval "print 'OR: OK' if 1 == 1 $opt 2 == 1";
0160154
2005/08/24(水) 21:58:28ID:???evalを使うことで、演算子の変数を展開して条件分岐してくれるようにはなったんですが、
演算子以外の変数が合った場合、なぜか上手く動作しません。
$data1 = "hogehoge";
$data2 = "foofoo";
$ptn1 = "hoge";
$ptn2 = "boo";
$opt = "or";
print "OK" if( eval"($data1 =~ m/$ptn1/) $opt ($data2 =~ m/$ptn2/)" );
欲しい結果は当然、OKです。
0161nobodyさん
2005/08/24(水) 22:02:14ID:???ダブルクオテーション囲んでるから、evalが解釈するのは
hogehoge =~ m/hoge/ or ...
になってる。
0163nobodyさん
2005/08/24(水) 22:06:32ID:???0166nobodyさん
2005/08/24(水) 23:13:17ID:PXiCgge7csvを読み込んで、表示するというプログラムを
書いていますが、データはShift_JISなので
Shift_JisをUTF-8に変換したいです。
ネットで調べるとJcode.pmが必要と書いてありました。
早速使ってみたところ、私が使っているサーバは
標準モジュールすら入っていないサーバなので
Jcode.pmだけいれてもダメでした。
そこで、友人のサーバでやろうと思っていますが
友人のサーバはperl5.0なんとかで
結構古いです。標準的なモジュールは入っています。
そこで質問です。
�@この環境にJcode.pmファイルだけ置けばうごくように
なりますか?
�AJcode.pmを置く事で他のperlプログラムが動かなくなったりしますか?
�BJcode.pmを置いてうごいたとして、shift_jisのまま表示するのと
UTF8に変換してから表示するのでは、処理のスピードに大きな
違いがでますか?
自己解決不可能だったため。。おねがいします。。orz
0167nobodyさん
2005/08/24(水) 23:23:23ID:???にしても5.0はねぇだろ。ちゃんと調べろ
0168nobodyさん
2005/08/24(水) 23:52:46ID:???0169nobodyさん
2005/08/24(水) 23:55:26ID:???0170nobodyさん
2005/08/25(木) 00:08:57ID:PZEhiYYsjcode.plはUTF-8未対応
分かってて書いてると思うがw
0171nobodyさん
2005/08/25(木) 01:32:53ID:???0172nobodyさん
2005/08/25(木) 08:22:01ID:???1. コピーで突っ込んだことが無いので、よく分からないけど、
最低でもJcode::*の辺りも必要だと思う。
2. それは無い。
3. UTF-8変換すると、かなり遅くなるはず。
telnet/sshが使える環境なら、そっちからきちんとインストールしたほうがいい。
>>167
5.004から動くはず。
5.005_03で動作してるよ。
0173nobodyさん
2005/08/25(木) 15:17:31ID:???そもそも166が使ってるサーバのPerlのバージョンがわからんと話にならん。
さらにサーバ会社も晒せば同じ環境に居る人が答えてくれるかもしれん。
0174nobodyさん
2005/08/25(木) 16:09:06ID:???>にしても5.0はねぇだろ。
「5.4」も酷いぞ。
>>171
5.8.1 以上の間違いだろう。
>>173
「標準モジュールすら入っていないサーバ」は @nifty (@homepage) の
別名と考えていいかと。そうなら 5.004 だか 5.005 だかその辺だったと思う。
>>166
他にもこういう選択肢もある。
http://search.cpan.org/~hio/Unicode-Japanese-0.27/
0175nobodyさん
2005/08/25(木) 17:18:03ID:???Encodeでいろいろやってみたもののうまくいきませんでした。
例えば、
while(<c:/bin/jane/Logs/2ch/ネット関係/WebProg/*.dat>) { }
みたいに、あるフォルダの下の全ファイルをさらうとかしたいのですが、
日本語が含まれているとうまくいきません。
どうすればよいのか、お願いします。
0176nobodyさん
2005/08/25(木) 18:01:49ID:???シフトJISでスクリプトを書くと、
use encoding "shiftjis";
を入れるとうまくいかず、入れないとうまくいきます。
(ただし、それを入れないと今度は他の日本語を扱う部分がおかしくなってしまいます)
0179nobodyさん
2005/08/25(木) 19:02:49ID:ZmEBADhu↓こんな感じ
こんにちは、Perlスクリプトについて質問があり・・・[長文のため省略しました。続きはこちら]
↑こんな感じで文章を省略したいんですけど、
区切ったバイトが2byte文字か判定する方法ってありませんか?現状文字化けしてます。。。
0181nobodyさん
2005/08/25(木) 19:57:49ID:???$str= = Jcode->new($str)->jfold($width);
で\n区切り。ただし途中の\nは無視する。
0182nobodyさん
2005/08/25(木) 20:00:24ID:???$st = Jcode->new($str)->jfold($width);
な。
0183nobodyさん
2005/08/25(木) 20:24:33ID:???$char_count = 10;
$body = "こんにちは、Perlスクリプトについて質問があります。";
$ascii = '[\x00-\x7F]';
$twoBytes = '[\x8E\xA1-\xFE][\xA1-\xFE]';
$threeBytes = '\x8F[\xA1-\xFE][\xA1-\xFE]';
@chars = $body =~ /($ascii|$twoBytes|$threeBytes)/og;
for ($count = 0; $count < $char_count; $count++) {
$str .= $chars[$count];
}
$strは「こんにちわ、Perl」となる
メンドくせ
0184nobodyさん
2005/08/25(木) 20:47:01ID:ZmEBADhuレスありがとうございます。自分はjcode使ってないのですが、それでうまくいくのなら試してみたいと思います。
>>183
この手のやり方を求めていました。
実際にやってみたのですが、うまくいきませんでした。
Shift-JIS限定のプログラムなのですが、Shift-JISではどのようにして日本語のフラグを立てているのでしょうか?
色々と検索しているのですが見つかりません。
0185nobodyさん
2005/08/25(木) 20:48:56ID:???0186nobodyさん
2005/08/25(木) 20:49:51ID:???文字列はEUC前提。
この場合なら、一回jcodeで$bodyをEUCに変換してから。
で、$strが完成したら、それをSJISに戻せば解決
0187nobodyさん
2005/08/25(木) 20:57:13ID:???0188nobodyさん
2005/08/25(木) 20:57:34ID:???でsjisでも正規表現がうまく動くと聞いているが俺は試してない。
だとしても>>183並にめんどくさいルーチンを通さなきゃいけない。
出力する文字コードがsjis固定でよいのなら
use Jcode;
$str = Jcode->new($str)->jfold($width)->sjis();
だ。
0189nobodyさん
2005/08/25(木) 20:59:29ID:???$str = Jcode->new($str)->jfold( $width, "<br>" )->sjis();
だ。
0190nobodyさん
2005/08/25(木) 21:47:57ID:ZmEBADhuところで、jcode通すと、半角カタカナが文字化けしますよね?
0191nobodyさん
2005/08/25(木) 22:06:41ID:???とかだけだと文字化けするケースがある
&jcode::convert (\$str, "euc", "sjis");
のように、変換前の文字コードを渡すことで解決できる場合もある
0192nobodyさん
2005/08/25(木) 22:37:57ID:ZmEBADhuなるほど!
0194nobodyさん
2005/08/25(木) 22:49:28ID:???スクリプトの文字コードをShift_JISにするか、
そのフォルダを示す文字列の文字コードをShift_JISに変換する。
0195193
2005/08/25(木) 22:58:37ID:???0196187
2005/08/25(木) 23:29:04ID:???■ このスレッドは過去ログ倉庫に格納されています