トップページ⇒php
1001コメント343KB

【Perl】初心者コーナー Part13

■ このスレッドは過去ログ倉庫に格納されています
0001nobodyさん02/05/30 13:06ID:R2kt1mTx
いらっしゃーい、Perlの「コーディング」で困ってる人のスレです。

1:自分はこう言う事がしたい。
2:それでこんな風にやってみたが・・・
3:それだとこんなエラーが出て上手く行かなかった。

1と3が無いと誰も答えられないよ。
良い回答は良い質問から。一緒に勉強しましょう。

CGIの質問は【CGIだけど、なんか質問ある? part 6】
http://pc.2ch.net/test/read.cgi/php/1019561283/
参考書籍の話題は【【Perl,CGI】参考書籍 第2版】
http://pc.2ch.net/test/read.cgi/php/988809842/
その他の雑多な話題は、【CGIに依存しないPerlの話題一般】
http://pc.2ch.net/test/read.cgi/php/991313362/
スクリプトの改造依頼は 【スクリプト改造工房 Part4】
http://pc.2ch.net/test/read.cgi/php/1012839651/

過去ログ、その他の役立ち情報は>>2-10あたりを見よう。
0751 ◆adminSE. 02/07/10 19:59ID:???
>>746

.htaacessでやるんじゃなかったっけ?

0752japh ◆J.5V8ta6 02/07/10 20:43ID:???
>>751
うわっ、何てカコイイトリップなんだ!
0753 ◆adminSE. 02/07/10 20:48ID:???
>>752

トリッパー使って3時間ほどadminで検索してたら偶然SE付きのがHITしますた
0754nobodyさん02/07/10 22:02ID:???
$fied[1]にはいってるすべての文字列【日本語含む】を@にしたいとき
$fied[1]=~tr/a-zA-Z_0-9\/.\n?-!"#$%&'()\=~|\{\`\+\*}_?><,\/\\\];@\[\\^-/@/cs;
↑このように書くしかないんですかね?
[a-zA-Z_0-9]以外の文字ぜんぶをあらわす特殊変数みたいなのありませんか。
0755nobodyさん02/07/10 22:03ID:01h+ntYo
[a-zA-Z_0-9]以外って、
[^0-9a-zA-z\_]じゃだめなの?
0756nobodyさん02/07/10 22:18ID:???
\W
0757nobodyさん02/07/10 23:13ID:???
>>750
!~ /^[0-9]+$/ のほうがさらに

0758nobodyさん02/07/10 23:23ID:???
=~ /\D/
じゃだめなの?
0759nobodyさん02/07/10 23:26ID:PCSWC5jP
CGIにデータを渡すときに、URLエンコードをしようとして

$arg =~ s/(\W)/'%'.unpack("H2", $1)/ego;

のunpack関数を使ってみたんですが、これだと、
最初の文字1文字しかエンコードされないですよね? 
例えば、
$arg=test.html?list=リスト&name=名前 
なんかだと、最初の「リ」だけじゃなく、
「リスト」と「名前」の該当する文字全部が
変換されるようにするには、どうしたらいいですか?
0760nobodyさん02/07/10 23:30ID:???
o が余計。
0761 ◆s/lF/2/o 02/07/11 00:24ID:???
一度だけコンパイルか
0762 02/07/11 00:28ID:???
>>759
おまいのegoがでてるよ。
0763nobodyさん02/07/11 00:48ID:???
>>762
ワラ・・・いかけた
0764nobodyさん02/07/11 01:10ID:???
(・w・)ブハッ! ワラテシマタ
0765nobodyさん02/07/11 02:32ID:???
(・∀・)ニヤニヤ
0766nobodyさん02/07/11 05:54ID:???
>>760, >>761
君たちは勘違いをしている。s/foo/bar/という構文の中で正規表現は
"foo"の部分だけなので例え"o"オプションをつけたからといって"bar"
のほうにはなんら意味がない。"o"は「正規表現」を一回だけコンパイル
するオプションであって置換内容をコンパイルするものではないという
事だす。

my $target = "AAAcccAAA";
for my $replacement ( qw/ bbb ddd / ) {
my $tmp = $target;
$tmp =~ s/ccc/$string/go;
print $tmp, "\n";
}
0767nobodyさん02/07/11 07:05ID:???
ヘッダとボディの区切りがもう出力されたかどうかどうやって調べるの?
0768nobodyさん02/07/11 07:13ID:???
↑こいつは一体何を言いたいのかさっぱり解らない

こっちから、また尋ねないと解らないような質問ヤメテくれ
0769nobodyさん02/07/11 07:21ID:???
>>768
説明がおかしかったですか。。例えば、

print "Content-type: text/html;\n\n";

こうゆうのが出力された後ならCookieに書くとかできないじゃないですか
だから、ヘッダが出力されているかどうか調べたいのですが。。
こういたことはできますか?
0770nobodyさん02/07/11 07:43ID:???
ソース追ってるのか
>print "Content-type: text/html;\n\n";
こう言うのを探せば良いんじゃ無いの?
端末側で吐いてる事確認したいのなら
オミトロンとかで吐き出せる
0771nobodyさん02/07/11 09:21ID:???
>>769
ヘッダとボディの区切りは改行

print "Content-type: text/html;\n";
print "Set-Cookie: name=value;\n";

〜〜〜 ↑ヘッダ 〜〜〜

print "\n";

〜〜〜 ↓ボディ 〜〜〜

print 〜〜〜
0772nobodyさん02/07/11 10:38ID:???
>>754
$fied[1] = '@' x length($fied[1]);
0773nobodyさん02/07/11 14:06ID:???
>>770
ソース追ってるってことではないです。。
>>771
それは分かっています。
区切りの改行が出力されたらもうヘッダに書き込めなくなるじゃないですか
だから、区切りの改行が出力されたかどうかPerlで調べたいです

こういったことはできないのでしょうか。
0774nobodyさん02/07/11 14:19ID:???
>>773
判断する必要性がない。
0775nobodyさん02/07/11 14:20ID:???
>>774
無理ってことですか?
0776nobodyさん02/07/11 14:26ID:???
ヘッダとボディの区別は一応あるが、perl内部ではprintで吐き出された結果に過ぎない。
perlではそんなことをいちいち区別してない。
0777nobodyさん02/07/11 15:13ID:/kd92Z8G
>773 perlはHTTPDのエクステンションじゃ無い、ただ標準出力に
printの内容を送るだけ、そのあとはhttpdの仕事
判断するなら771の言うように改行を調べれば良い。
0778 ◆JAPH9PWA 02/07/11 16:29ID:???
>>出力を見張る

our $headers_end;
sub myprint
{
$headers_end = 1 if /^$/;
print @_;
}

とか、どう?。
printをオーバーライドしてもいいかも。


# >>753 トリップ変えました。ありがとう
0779 ◆R7.pelK2 02/07/11 18:33ID:???
test
0780 ◆adminSE. 02/07/11 18:34ID:???
>>778

どういたしますて
0781nobodyさん02/07/12 02:47ID:???
http://pc.2ch.net/test/read.cgi/php/1026141215/ から

> GDモジュール、どうしても使えない。。
>
> 1 :nobodyさん :02/07/09 00:13 ID:k+y90VS+
> サーバはWebARENA Suite、
> GD.pmを使おうと
> サーバにコンパイル済みのGD1.27をアップするがどうしても
> うまく動かない。
>
> perl: error in loading shared libraries: ./auto/GD/GD.so: undefined symbol: gdImageJpegPtr
>
> こんなエラーが出る。。
> どうすればいいのか。。
> WebARENAはPerlは5.0.503だから、その環境でコンパイルしたものを選んだ。
> なぜだ、、何が、、いったい。。
078278102/07/12 02:47ID:0osVMAyz
>>781 続き

例によって親切には説明するつもりはないのでそのつもりで。

1. とりあえず telnet.cgi をまともに動かして。
2. gd-1.8.4.tar.gz(libgdのソース)というふぁいるをGETして。
3. CPANよりGDモジュールのソースふぁいるをGETして。
4. 二つのファイルをtelnet.cgiと同じdirにUPして。
5. 二つのファイルをtarで解凍して。
6. インストール先dirをcgi-bin以下にlib,include,bin,man作成
7. gd-1.8.4/Makefileを編集(インストール場所を6で作成したdirに設定)
8. gd-1.8.4をmake; make install
9. GD-1.40/Makefile.PLの
  $DEFINES .= ' -DHAVE_XPM' if $XPM;
  をコメントにする。
10. GD-1.40のDIRで[ perl Makefile.PL LIB=/virtual/おまえのIP/cgi-bin/lib/perl5 INSTALLMAN3DIR=/virtual/おまえのIP/cgi-bin/man/man.3 ]実行
11. 10で出来たMakefileに8でインストールしたgdへのLIBパスとINCパスを追加して,X関連のリンク(だっけ?-lx11とか)を削除
12. make; make install
13. GD使うスクリプトの冒頭で #!/usr/local/bin/perl -I../lib/perl5/i386-linux とでもしてくれ。
15. あとはてめぇでがんばれ。
16. 意味がわからん?ってか,わからんならやらないでくれ。他に迷惑がかかるかもしれんし。

とりあえず,demo/gd_example.cgi は動いたぞ。
# /usr/libにlibgdがあるのにヘッダがない罠…。

いくらわからんからって単発スレは立てないでくれ。
あなたのスレ立てのために他のスレがdat落ちするじゃね〜かよぉ〜。
0783nobodyさん02/07/12 04:33ID:???
>>781
なんだか偉そうだな。
とりあえず、共有サーバでコンパイルするのはやめてほしい気分。
0784nobodyさん02/07/12 12:08ID:???
素朴な質問です。
if($name eq ''){print "hoge";}
と
print "hoge" if(!$name);
は処理的には同じに思うんですが
書き方以外に何か違う意味とかってあるんですか?
0785 ◆JAPH9PWA 02/07/12 12:45ID:???
>>784
それは処理的に同じではないよ。
$nameが単なる文字列なら結果としては同じことだけど、
もし$nameがオーバーロードされた文字列なら、全く違う結果になることはありえる。

まぁそんなことを聞きたいんじゃないと思うけど、
質問する場合はその辺を簡略化してよ。

で、
if(foo){ bar }
と
bar if foo;
は同じこと。ちなみに
foo and bar;
も同じ。
書き方意外に違う意味は「読みやすさ」だね。
自分が文脈に合う、読みやすい、と思う構文を使えばいいよ。
0786nobodyさん02/07/12 12:47ID:???
>784
$name = "0";
の時に変わるな。
0787 ◆JAPH9PWA 02/07/12 12:57ID:???
>>786
あう、そういえばそうだ。
単なる文字列だとしても別の意味をもつ文だね。
078878402/07/12 14:42ID:???
>>785
なるほど。勉強になりました。
ありがとうございました。
>>786
そういえばそうでした。
鋭いご回答ありがとうざました。
0789nobodyさん02/07/12 17:48ID:???
# 排他処理をしたいです。
# ローカル環境(WindowsMe+Apache+Cygwin付属のPerl)では成功するのですが、
# サーバで実行するときには、必ず失敗します。
# コーディング上の落ち度がありましたらご教授ください。
sub create_lock {
  my ($lockfile, $retry) = @_;
  while (!mkdir($lockfile, 0755)) {
    if (--$retry <= 0) {
      return undef;
    }
    sleep(1);
  }
  return 1;
}

sub remove_lock {
  my ($lockfile) = @_;
  rmdir($lockfile);
}

#上記関数の利用例
my $lock_handle = &create_lock($dir_lock, $lock_retry);
if (not $lock_handle) {
  &print_error($resource{writedatafailed});
}
#ここで処理する
&remove_lock($dir_lock);
079078902/07/12 17:48ID:uV0iCTit
あげわすれました。すみません。
0791nobodyさん02/07/12 17:53ID:???
排他処理は専門スレがあるよ。
ttp://pc.2ch.net/test/read.cgi/php/1024795138/
079278902/07/12 18:03ID:???
>>791さん、ありがとうございます。そっちにいきます。
0793nobodyさん02/07/12 19:41ID:mbAMx/DL
すいません、質問させてください。

タブ区切りの表から、一行ずつ取得し、grepで検索をかけ、
マッチしたものとマッチしなかったものの一覧を作成したいのですが

・条件に、検索キーワードは複数。(or形式)
・行末に、ヒットしたキーワードのみ挿入(複数のうち、該当した物だけ)

というものがあります。
その時

if(grep /$kw{$key}/,@line){#配列の中にキーワードが入っているなら
chomp @line;
if($check_flag == 0){
push(@result,@line);
push(@result,$kw{$key});#resultに追加
$check_flag = 1;#別のところでフラグに使っている
$flag = $line[0];#別のところでフラグに使っている
$no_count = 1;#一回目かそうで無いかのフラグ
push(@result,"\n");#行末にキーワードをつける
}elsif($check_flag == 1){#二回目からはキーワードのみを最後につける
push(@result,$kw{$key});
$no_count = 1;

とした時、配列の最後に$kw{$key}をpushで押し込むと、強制的に改行が入ってしまいます。
かといってchompをすると、全部改行が消えてしまい、全部のデータで一行扱いになってしまいます。
どうにか最後の改行のみ消す方法はありませんでしょうか?


取得した行+キーワードx個
取得した行+キーワードx個
・
・

というような表を、上記のスクリプトに手を加える程度で
作成することは可能でしょうか?

すいませんが、わかる方がいらっしゃいましたらご教授ください。
0794nobodyさん02/07/13 00:01ID:???
>>793
とりあえず突っ込んでおこう。↓は何ですか?
push(@result,"\n");#行末にキーワードをつける

あと$kw{$key} に改行が含まれる可能性は?
つーかそもそも if (grep /$kw{$key}/, @line) { 〜でやりたい事が出来るのかねぇ。疑問だよ。
0795nobodyさん02/07/13 01:13ID:???
Perlのスクリプトの試用版を配布するときに、ソースを見られなくするには、
どうすればよいでしょうか。

バイナリ化して、プロテクトをかけると聞いて調べたところ、
バイナリエディタというものを見つけましたが、
プロテクトの仕方がどうしても解かりません。

プロテクトするほどのソースは書けませんが、
どうかよろしくお願いします。
0796nobodyさん02/07/13 08:29ID:???
>>795
コンパイルしてしまうか、Perl2EXEなどを使うしかないと思われ。
0797nobodyさん02/07/13 22:35ID:xEQW3A4y
名前:年齢
A  :22
B  :31
C  :13

上記のような二次配列を連想配列をつかって作成したのですが、
これをソートするのはどのようにすればいいのでしょう・・?
知人の考えで、年齢をハッシュのキーにしてソートすると言う案があったのですが、
同じ年齢の場合には、上書きされてしまうのでその案は使えませんでした。
どのようにすればいいでしょう・・?
0798nobodyさん02/07/13 22:49ID:???
foreach(sort {$hash{$a} <=> $has{$b}} keys %hash){
print qq($_ : $hash{$_}\n);
}
0799nobodyさん02/07/13 22:49ID:???
タイプミススマソ。
適宜修正して。
0800nobodyさん02/07/13 23:28ID:???
795>>796さん、お答えありがとうございます。
今、ラクダ本で、コンパイルについて見ています。

しかし、use Protect ;とファイルにはあるのですが、
この Protectの部分について書かれていません。

use Protect ; は、どうやればできるのでしょうか。

0801 ◆JAPH9PWA 02/07/14 00:45ID:???
>>800
ラクダ本のどこだかわからないが、
それは「自分でプロテクトモジュールを作成してね」という意味だと思う。
とりあえずそれを実装するには、
・Perlに構文の理解
・CPANのFilterライブラリの使用法
・暗号化ライブラリの使用法
が最低限必要だと思うよ。
0802お酢カル ◆myMazZ7Y 02/07/14 01:07ID:???
>>801
説明できないオナニー野郎は(・∀・)ウセロ!!

まぁ>>800は馬鹿だからこれでいいかと
------------encode-------------------
while(<>){
$n= unpack "h*", "$_";
$n=~y/123456789fedcba/abcdef987654321/;
$e= pack "h*" , "$n";
print $e;
}
0803nobodyさん02/07/14 01:08ID:???
800>>801さん、ありがとうございます。

googleで、検索していたのですが、use MD5; というのは、
見つけました。
私には、まだ敷居が高そうです。

e-shoppyというSHOPスクリプトの試用版にバイナリエディタを
使うようにあったので、試用版って、こんな感じで配布しているんだと
思い、気になるので調べていました。

スクリプトを売る前に、試用版として、こんな感じで配布すれば、
ソースがプロテクトできるので、有用だなと興味を持ちました。

0804nobodyさん02/07/14 02:43ID:vNhQYRiQ
質問させてください。
今、perlでBBSを書いているのですが、
大体できて知り合いの所に入れてもらったりして
動作確認しました。

色んな環境の人のところで正しく動作したのですが、
(perlのバージョンが5.5or5.6,実行権限がnobody,オーナー等)
一人だけ動作がおかしい人がいるんです。

何がおかしいのか調べてみたら、
サブルーチンでseekさせてメインのルーチンに戻ってくると
seekさせたのが無かったことに?なってるんです。
サブルーチンでどんなにseekさせても
メインのルーチンで続行するとなぜか次の一行は空行、
その次の一行はファイルの一行目を読み込みます。

そのおかしくなる人の環境は
OS NAME = freebsd
PROCESS ID = 5854
PERL EXECUTABLE = /usr/local/bin/perl
PERL VERSION = 5.00503
ってな感じです。権限はオーナー権限です。
他の、perlのバージョンが5.5の人のところではちゃんと動いてます。
この人の環境になにか特別なものがあるとは思えないので、、、
ただ、他の人はみんなlinuxなんですけどそれって関係ありますか?

コーディングの問題かとも思っていろいろ試行錯誤してるのですけど
もう分からないんです・・・
0805nobodyさん02/07/14 02:51ID:CbCEC3kH
>>804
ソースもどこかにアップしてみてよ。
0806nobodyさん02/07/14 03:15ID:???
804です。
UPしてみました。なにぶん、perlでの初めてまともな作成物なので
見るのも辛いところもあると思いますが、よろしくお願いします。
ttp://naha.cool.ne.jp/b3b3b/styx.zip
0807 02/07/14 03:23ID:???
アーカイブじゃなくtxtだとすぐ見られるのだが・・・
0808nobodyさん02/07/14 03:25ID:???
ライブラリに分割してあって txt だときっついです。。。
もうしわけないです;;
0809nobodyさん02/07/14 03:42ID:CbCEC3kH
1つおもいあったったのが、たとえばサブルーチン delete_art などにおいて、
sysread関数と他の方法による読み込みの混用が存在しています。

これは、わたしの手元のラクダ本に書いてあることですが、これらの混用は、
あなたがウィザード級の腕前の持ち主でないかぎり推奨できないとあります。
0810nobodyさん02/07/14 04:04ID:???
804です。アドバイス有難うございます。
どっかのサイトで行数を数える一番効率の良い方法ってのが出ていまして、
sysread使ってましたので、行数を数えるのにsysread使ってます。

sysread使わないで書き直してもみます。
いまおかしくなってる環境の当人に連絡が取れないので
今すぐには無理だと思いますが。

ただ、殆どの人のとこでは正常に動いていて
その人のとこでだけ動かないっていうのが気になります。
環境に依存するような問題があるのでしょうか?
(ファイルを扱う関数の、実装の違いとか)

らくだ本欲しいですけど
貧乏なので本屋で眺めるだけです;;
perl は立ち読みと WEB と皆さんの素晴らしい作品で勉強中です。
0811nobodyさん02/07/14 04:15ID:CbCEC3kH
>>810
恐らくではありますが、FreeBSD環境では sysread関数と他の読み込みの混用の
面倒をみてくれないということでしょう。
sysread関数というのは、直接システムコールを呼び出しているので混用した
場合に処理に見合った動きが期待できなっかったりするようです。
まぁ、単純に sysread関数を read関数に書きかえるだけで恐らくうまくいくで
しょう。

それから、効率よく行数を数えるのなら以下をやってみてはどうでしょう。

while (<FILEHANDLE>){}
print "全行数は: $.\n";
close(FILEHANDLE);
0812nobodyさん02/07/14 04:24ID:???
while (<FILEHANDLE>){}
最初はこういう方法とっていたのですが、速度が良くないようです。
ベンチとりまくってみましたが、
バッファにsysreadで読んでtrするほうが圧倒的に早かったです。
1000レスとかになるログだともろに差が出てきたので、、、

read で書き直して、ベンチマークと相談して
当人にためさせてみますね。

あと、問題の出ている個所の本元は、&std::pick だと思います。
ここでもsysreadで行数数えているので、ご指摘の問題があるのだと思います。

でもおかしいんですよね、、、
このpickルーチンだけ抜き出した簡単なテスト用cgi作って
彼にためさせたらちゃんと動作してたんですよね。
(任意の行にseekちゃんとしてる)

パッケージとか絡むとなんか違うのかなぁ〜
0813nobodyさん02/07/14 04:29ID:CbCEC3kH
>>812
速度の差なんて人間の感覚では気づかない程度のミリ秒単位だからそう
気にすることないと思います。 もしこれが遅いのならC言語などで書く
ようにすることを考えるべきです。
0814nobodyさん02/07/14 04:44ID:???
ミリ秒の差だと思ってベンチとって見たら
0.数秒の差だったです・・・

テストケースのログで、
(BBSのトップに○○スレのそれぞれ最新の○件を表示みたいな)
そのスレが1000レスとかあると、一行目からたとえば950行目を探すのに
while (<FILEHANDLE>)式とtr式で物凄い差が出ました。
それが20スレとかあるともう体感できそうなくらいの差だったので。

ベンチマーク用のルーチン作って2000行のログのうち**行目をサーチする、
というのを1000回まわすのを自宅でやってみたところ
tr式の方が15倍くらい早くて、
従来の方法だと固まったんじゃないかってくらい遅かったです(もう一分位;;)

BBSで使う場合1000回も回さないですけど
それでも標準的表示数で0.15秒くらいの差が出てました。

私はもともと最初にプログラムを触った時
みんなマシンパワーがなくてなんでも高速化高速化があたりまえの頃だったので
なんか貧乏癖がついてるのかもしれません。
perlで久しぶりにプログラミングってのを再開してます。

もうちょっとおおらかにプログラミングしてみます。
いろいろ有難うございました。
0815nobodyさん02/07/14 04:48ID:CbCEC3kH
>>814
0.1秒でも速くしたいのなら別ファイルに常に行数のみを保存しておく
などの方法もありますが、そこまでしてもPerlで速く処理させたい?
0816nobodyさん02/07/14 05:02ID:???
別ファイルに行数保存してますよ〜
でも任意の行数にシークするってのはできないですよね。
(関数としてはない)ユーザーが工夫しないと。

書き込みがあったとき、削除のとき、だけは再度行数を取得してます。
もし、別ファイルが不慮の事故でいかれてたら一生ずれたまんまになるので。

perlでそこまでして、とは思ってないです。
生意気そうなこと言って申し訳ありません。
でも出来るだけ早く出来るならそのほうがいいかな〜ってだけです。

c-boardのソースとかみたらなんかすごくてブルーなっちゃって
高速化しないとだれも相手にしてくれないかな、って囚われていました。
早くしなきゃ、早くしなきゃって。
でも殆どの人はそんなこと気にしてないんですよね。

それと単純にベンチで段々確実に改良ごとに早くなってくのが
楽しかった、ってのもあります(笑

まだまだ勉強中の身ですので努力して良い物作れるようにがんばります〜
0817高速化遊戯02/07/14 05:46ID:Iun5VHk7
別ファイルに、行頭のファイルポインタの一覧を保存する
というはダメですかね?
任意の行に飛ぶ時はこっちをループでまわして
得られたファイルポインタの所にseek、と。
余計なデータが無い分、ループまわすのも早そうだし。
試してないからなんとも言えないけど。
0818nobodyさん02/07/14 12:11ID:???
804です。
大して技術も基礎もなってないのに
しかもperlで高速化とか言ってるのは
よく思われないみたいなので、もう言うのやめようと思ったのですが
高速化遊戯さんがレス下さってるので、書きます。

別ファイルだと、結局そのファイルを何らかの形で取り込まないといけないです。
while (<FILEHANDLE>){}が遅いのってベンチとってないから
断言できないですけど、ファイルの大きさうんぬんより
perlの持ってるファイルから一行取り出すための作業が
遅いんじゃないかと思ってます。(憶測で物言ってすみません)

それだったら、もとのファイルの各行にインデックスつけた
データ形式にして、
もしそれが数千行とかあるファイルだったらですけど
いくらかずつseekさせて、インデックスを拾い読みして
目次見たいの作って、任意の行を拾うときは、
その目次見て近そうなとこから探すほうがいいかと思いました。

つづく、、
0819nobodyさん02/07/14 12:19ID:???
俺はデータファイルの頭に、100行毎にファイルポインタ記録してるよ
ここみたいなBBSで、一応10000レスをリミットにしてるから
9桁(ファイルポインタ)×100 = 1KB程度がインデックスに使われてる

その代わり読み込み時の落ち込みは少ない
レス5850を読む、なら5800行目のfpを探してseek
そこから普通に行処理するだけだから。

後はファイルのお尻〜行を読むtailみたいメソッドを書いてる位。
perlで低レベルの関数使うのは面倒だから、どうしても行読み出しで
グルグルしがちだけど
工夫すれば極端なパフォーマンス低下は防げると思うよ
0820nobodyさん02/07/14 12:22ID:???
お、今書いてるのか ⊂(´ー`⊂⌒ヽつ

>perlの持ってるファイルから一行取り出すための作業が
>遅いんじゃないかと思ってます。(憶測で物言ってすみません)

俺もそう思う。テストした訳じゃ無いけど
sysreadでバイト読みする方がずっと早いと思うよ。
だからと言って、Cでもperlでも低レベルの関数はそれなりに
使い辛い訳で・・・
0821nobodyさん02/07/14 12:23ID:vNhQYRiQ
最初、そういうのを考えたのですが
もうログの形式を変えたくなかったのでやめました。

それにせいぜい1000行前後なので直接改行の数を数えることにしました。
それで書いたルーチンが次のようなものです。
(勉強中なのでおかしいとこあると思いますけど、、、)

sub pick {
  my $fh = shift;
  my $hit = shift;
  my $bufsize = 4096;
  my ( $per, $buf, $line, $prev );
  seek( $fh, 0, 0 );
  binmode $fh;
  while ( sysread $fh, $buf, $bufsize ) {
    $prev = $line;
    $line += ( $buf =~ tr/\n// );
    last if $line >= $hit;
    $per++;
  }
  my $over = $hit - $prev;
  $buf =~ /(^([^\x0D\x0A]*\x0D?\x0A?){$over})/;
  seek( $fh, $per * $bufsize + length($1), 0 );
}

これでベンチとってみたらびっくりするくらい早かったです。
一行ずつかぞえるのの、15倍くらいの速さでした。
数千行あるようなファイルをいくつもまわす場合は明らかに
体感できるくらいの差がでました。
それで嬉しくて調子のって使っちゃったです・・・

でも良くないようなので、他の方法探してみます。
(FreeBSDだけなのかな?、ダメなのは)
0822nobodyさん02/07/14 12:32ID:???
>>821
最近コード書いてないんで殆ど忘れちゃったんだけど
俺も>>809さんの言うとおりだと思う
Cで速度を求めてfgetsからreadにした時に、そう言う問題に嵌った事有るよ
良く覚えて無いんだけど、結局は低レベルと高レベルの読み込み関数を
併用したのが間違いだったと思う
0823nobodyさん02/07/14 12:38ID:vNhQYRiQ
>俺はデータファイルの頭に、100行毎にファイルポインタ記録してるよ

うわぁ、それスマートです;;
とても勉強になります。
今作ってるのはもう固まってきちゃってるので
大きいバージョンUPの時にでもそういう手法でやってみます。
いぱーいレスつけられますもんね〜

>perlで低レベルの関数使うのは面倒だから、どうしても行読み出しで
>グルグルしがちだけど

うんうん。地が貧乏性なので、配列にごっそりとかぐるぐるとか
なんか疑問に思っちゃって。

いろんなBBSのスクリプト見たりあさったりしたんですけど
意外と、みんなぐるぐるで、グルグルでいいんかよ〜って思ってたんです。
だからこういう具体的な工夫例聞けてとてもやる気でました。
0824nobodyさん02/07/14 12:40ID:???
と言う訳で819の方法は我ながらお勧めなんだけどなあ(w
ログのコンバータ書いた方が後々苦労しない気もしないでもない。
これだとシステムよりの関数は一切使ってないから
つーか1000行程度ならぶん回しても問題無いんじゃない?
0825nobodyさん02/07/14 12:41ID:???
優良スレ認定
0826nobodyさん02/07/14 12:42ID:vNhQYRiQ
問題の解決の糸口については、皆さんのアドバイスのおかげで
つかめてきたのでこれから色々その線でしらべて見ようと思います。
0827nobodyさん02/07/14 12:45ID:???
わはは頑張って下さい、
〜〜する清原みたいなバカスレが再現出来ると結構嬉しいもんです(・∀・)
0828nobodyさん02/07/14 14:31ID:ZiG6NcZV
perl初心者ですが、よろしくお願いしますです。
現在、赤帽7.2の上にRPMとして乗っかっているPerlのバージョンは、5.6なのですが、
ある既製のPerlスクリプトを使いたいのです。
そのPerlスクリプトは、Linux上でJperlを必要としているのですが、
私が探した範囲では、Linux用のJperlのパッチは、5.005ベースのものしかありません。
パッチをあてようとしてもうまくあたりません。

この、Jperlを必要としているPerlスクリプトをLinux上で動かすには、
どのような解決策があるのでしょうか。どなたか、よろしくお願いしますです。
0829nobodyさん02/07/14 14:33ID:???
なぜjperlが必要なのか調べ、jcode,pl、Jcode.pmにその個所を置き換える。
0830nobodyさん02/07/14 15:00ID:xUfIRkak
>>828
Jperlを必要とする既製スクリプトってたいしたことなさそうだから、
一から自分でコーディングしてみては?
0831nobodyさん02/07/14 15:29ID:ZiG6NcZV
>>829
>>830さん
レスありがとうございます。確かに、その通りなんですが、
1>そのスクリプトが200KBほどある
2>日本語の文章の構造解析のスクリプトなので、日本語処理がチョット複雑
3>あくまでもテストとして、ちょっと動かしてみたいだけなので、できるだけ手間を
かけたくない
という理由で、Perl5.005のソースをDLして、それにパッチを当てようと思っていた
のですが、Perl5.005のソースがなんか見当たらないのです。
0832nobodyさん02/07/14 15:52ID:???
> Perl5.005のソースがなんか見当たらないのです。

簡単に見つかる予感。
083383102/07/14 16:00ID:ZiG6NcZV
>>832
ググルで、"perl5.005 src"で見つけました。
すんませぬ。"perl5.005 source"とか”rpm"とかで検索していたオラが
間抜けでした。逝ってきます。
Perl暦2日なんで、許してやってくだされ。
0834nobodyさん02/07/14 19:04ID:???
sysopenに使うパラメータとかなんだけど、

O_RDONLY = 0
O_WRONLY = 1
O_O_RDWR = 2

とかは分かってるけど

O_APPENDとかは?
検索してもヒットせず…
おしえてくらはい
0835nobodyさん02/07/14 20:53ID:???
>>834 追記以上の説明が必要なん?
http://www.linux.or.jp/JM/html/LDP_man-pages/man2/open.2.html
大体こんな所でしょ
0836nobodyさん02/07/14 21:01ID:???
ああ、割り当てられてる番号か
それって歴史的に環境依存だから0.1位しか信用出来ないよ?
0837二つ目のお気に入りとして使って02/07/14 23:31ID:gWk8eFjt
今までに無かったrink集です。ナビ
ゲーションリンク機能を使って右フ
レームにリンク先をさくさく表示。
今までのリンク集のようにいちいち
戻らなければならないなんてことは
ありません。

http://home9.highway.ne.jp/cym10262/
0838nobodyさん02/07/15 00:06ID:???
ファイルのコピーってどうやれば出来ますか?
元ファイル開いてメモリに読み込んで別ファイルに書き出すじゃメンドイし
どの環境でも使える方法でなんか一発でする方法ないですか?
0839 02/07/15 00:09ID:???
>>838
copy a b
0840nobodyさん02/07/15 00:18ID:???
>>838
Perl5なら以下で出来る。

use File::Copy;
copy("file1", "file2");
084183802/07/15 00:24ID:???
>>840
有難うございます、上手く出来ました。

>>439
やってないけどそれだと多分エラーです。
0842 02/07/15 00:25ID:???
>>841は>>439のなにがエラーなんだ?
084383802/07/15 00:32ID:???
>>842
やってみたらやっぱりエラーが出ました。

String found where operator expected at test.cgi line 1, near
(Do you need to predeclare copy?)
syntax error at test.cgi line 1, near "copy "a.txt""
String found where operator expected at test.cgi line 1, near
(Missing operator before "b.txt"?)
Execution of test.cgi aborted due to compilation errors.
0844 02/07/15 00:36ID:???
>>843

>>439は絶対やっちゃダメだぞ。
犯罪だからな。エラー云々以前の話だ。
がんがれよ。
0845nobodyさん02/07/15 00:41ID:???
>>843 通報すますた
084683802/07/15 00:54ID:???
>>844
マジですか、っても明らかにおかしいのでローカルでしかやってませんが。
今後気をつけます。
0847nobodyさん02/07/15 07:25ID:???
もし$dataに&もしくは=のどちらか一方でも含まれていなかった場合は終了する
という場合は

if(($data !~ /&/) || ($data !~ /=/)) {exit;}

こうでいいんでしょうか?
0848nobodyさん02/07/15 07:59ID:Gdw1y7VE
exit unless $data =~ /[&=]/;

私も初心者だから違うかもしれないけど
0849nobodyさん02/07/15 09:00ID:AMXAGLXX
>>847
聞くより試した方が早いだろうに。

exit if(index($data,'&') == -1 || index($data,'=') == -1);
こっちのが数倍軽い。美しくは無いが。
0850nobodyさん02/07/15 09:42ID:???
>>847
exit unless $data =~ tr/&=//;

■ このスレッドは過去ログ倉庫に格納されています