68user's page 掲示板

Prev< No. 2239〜2265> Next  [最新発言に戻る] [過去ログ一覧]
No. 2239 # mo 2001/11/01 (木) 01:20:40
こんにちは 
Perlについて質問させてください。

%aa=(a=>1,b=>2,c=>3);
%bb=(a=>4,b=>5,c=>6);
%cc=(%aa,%bb);

これでは%cc は a=4,b=5,c=6 のように上書きされてしまいます。
%cc が a=5,b=7,c=9 になるようにするにはどうしたらいいのでしょうか

よろしくお願いします。 

No. 2240 # ふくし [E-mail] 2001/11/01 (木) 02:04:05
#質問で迷惑掛けてるので答で貢献;;;

mo さん、はじめまして。

%aa=(a=>1,b=>2,c=>3);
ていうことは、
$aa{a} = 1;
$aa{b} = 2;
$aa{c} = 3;
と同じです。

a = 1;
b = 2;
c = 3;
ではないです。

%aa はハッシュというものを作っています。
お手もとの参考書などで「ハッシュ」という言葉を調べてください。

で、%bb=(a=>4,b=>5,c=>6);
ていうことは、
$bb{a} = 4;
$bb{b} = 5;
$bb{c} = 6;
と同じです。

%cc=(%aa, %bb);
ということは、上の結果、
%cc=(a=>1,b=>2,c=>3,a=>4,b=>5,c=>6);
と一緒なので、
$cc{a} = 1;
$cc{b} = 2;
$cc{c} = 3;
$cc{a} = 4;
$cc{b} = 5;
$cc{c} = 6;
と一緒なので、結局 $cc{a}、$cc{b}、$cc{c} は2回代入されるので、
後のほうが有効になって、
$cc{a} = 4;
$cc{b} = 5;
$cc{c} = 6;
となっているわけですね。

で、この場合、$cc{a}、$cc{b}、$cc{c} には、
それぞれ $aa{a}、$aa{b}、$aa{c} と $bb{a}、$bb{b}、$bb{c} の
合計が入って欲しいわけだから、
%cc = (a => $aa{a}+$bb{a}, b => $aa{b}+$bb{b}, c => $aa{c}+$bb{c});
とするか、
foreach (a..c) { # $_ が a から c までくりかえし実行
    $cc{$_} = $aa{$_} + $bb{$_};
}
とするか、%aa、%bb にどんなキーが入っていてもいいことにするには
foreach (keys %aa) { # $_ に %aa のキーを次々に入れながら繰り返し実行★
    $cc{$_} = $aa{$_} + $bb{$_};
}
とするか、
%cc = map {$_ => $aa{$_} + $bb{$_} } keys(%aa);
とするか。

★がついたのが一番おすすめか?
foreach、keys、a..c、map については適当な本を調べてください。(ひでえ、、)

とりあえず
foreach (a..c) {
    print "$_\n"
}
とか
foreach (keys %aa) {
    print "$_\n"
}
とか、
@x = (1..5);
@y = map{ $_ * 2 } @x;
foreach (@x) {
    print "$_\n";
}
とか動かしてみると面白いと思います。

#もっとあっと驚く回答があったら教えてください

No. 2241 # ふくし [E-mail] 2001/11/01 (木) 10:30:56
すいません

下で
foreach (a..c) {
と書いているのは
foreach ('a'..'c') {
と書かないと怒られます。(警告だけで、動作はするようです)

ようは、a、b、c は変数の名前でなく文字列で、
%aa、%bb、%cc というハッシュのキーですね。
%aa というハッシュの、キーが 'a' の値にアクセスするには
$aa{'a'} と書きます。ただしこの場合 a はハッシュのキーであると
はっきりしているので $aa{a} と省略形で書けます。

同じハッシュでキー x の値に 550 を、キー y の値に 660 を入れるには
キーと値を交互に指定するリストを使って
%aa = ('x', 550, 'y', 660);
と書きますが、キーと値の関係をはっきりさせるために
カッコの変わりに => という記号を使えば
%aa = ('x' => 550, 'y' => 660);
と書けます。で、この場合は => の左側はハッシュのキーなので
省略して
%aa = (x => 550, y => 660);
とも書けるわけです。
でも、この '' 省略方式だと、
空白を含むキーが使えません。
%kg = ('yamada tarou' => 80, 'satou tamao' => 50);
だと
$kg{'yamada tarou'} に 80 が、$kg{'satou tamao'} に 50 が
入りますが、
%kg = (yamada tarou => 80, satou tamao => 50);
だとエラーが出て動きません。
$kg{yamada tarou} も怒られて動きません。

下のプログラムで a, b, c というのは、
ハッシュのキーで「文字列」であることを覚えておいてください。

No. 2242 # mo 2001/11/01 (木) 23:53:58
ふくしさん、 こんにちわ

map の使い方はまだ理解できませんが
★のコードは理解できました。

ありがとうございました。

No. 2243 # sio 2001/11/02 (金) 17:35:45
はじめまして。
2日前から調べているのですが、解決できずにここにたどり着きました。

CGIからCGIへデータを渡す際に
  print "Location: test.cgi?data=1\n\n";
ではなくPOSTでデータを渡したいのですが
Socketを使うというのを発見し、いろいろ試したのですが
まるで駄目です。(Socket自体、今まで使用したことも無いので(^^;)
具体的には送信元のCGIをindex.cgi、受信するCGIをtest.cgiとしますと
index.cgiに下記のような記述をしてみたのですが
test.cgiには何を書いてよいのかすら分かりません。
ご教授頂けないでしょうか
よろしくお願いします。
================================
#!/usr/local/bin/perl

use Socket;
$server='www.*****.com';
$port = 80;
$port = getservbyname($port,'tcp') unless $port =~ /^\d+/;
$iaddr = inet_aton($server)
                or die "$serverは存在しないホストです。\n";
$sock_addr = pack_sockaddr_in($port,$iaddr);
socket(SOCKET,PF_INET,SOCK_STREAM,0)
                or die "ソケットを生成できません。\n";
connect(SOCKET,$sock_addr)
                or die "$serverのポート$portに接続できません。\n";
select(SOCKET); $|=1; select(STDOUT);

$file='test.cgi';
$query='data=1';
$len=length($query);

print SOCKET "POST $file HTTP/1.0\r\n";
print SOCKET "Content-Length: $len" . "\r\n\r\n";
print SOCKET "$query";

================================

No. 2244 # iwta 2001/11/03 (土) 03:48:28
こんな感じでは?

if ($ENV{'REQUEST_METHOD'} eq "POST"){ read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }

@pairs = split(/&/, $buffer);
foreach $pair(@pairs){
    ($name, $value) = split(/=/, $pair);
    $value =~ tr/+/ /;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
    $FORM{$name} = $value;
}

$data = $FORM{'data'};

って、よくある掲示板のパターンですけど。(はずしてたらごめんなさい)
というより、index.cgi は普通にフォームを使うだけでことは足りないのでしょうか? (Socket を使わずに)

No. 2245 # sio 2001/11/03 (土) 18:24:11
補足・その他です(^^;

main.cgi→index.cgi→test.cgi
となっていて
main.cgiでフォームを使いindex.cgiにpostでデータを送信しています。
この受け取ったデータをtest.cgiにそのまま渡したいのですが、
その方法で悩んでいます。
test.cgiはメンバー入り口で受け取った会員ナンバーによって
それぞれのページデータを読み込み表示するスクリプトになっていますので
直接
http://***.com/test.cgi?ID
などとされて入室されるのは避けたいのです

さらに考えた結果、index.cgiとtest.cgiをまとめてしまえば良い事に気付きました(^^;

ですが、今後の為にもSocketを使えるようになりたいので
もうちょっと努力してみます。

iwtaさんありがとうございます。
受け側では標準入力で良いのですね。
<SOCKET>をいろいろいじってみたりしてました。。。
ということは受けるほうでは
use Socket;
は不要なのでしょうか

Socketの文献をいろいろ読んだのですが、POSTについての情報がどこも少なく
(英文は読んでませんが)
いろいろとお尋ねしてお手数をおかけします。

No. 2246 # 68user 2001/11/03 (土) 19:14:11
>>2232 名無しさん
ご指摘ありがとうございます。どうやってわかりやすく説明するかは
非常に悩むところですね。autoflush は「存在自体あまり知られてない」
という痛い欠点があり、難しいところです。次回更新時に何かしら
わかりやすい解説を書きたいと思っています。

>>2235 H-Hash
> このたび、RFC2616の日本語訳のURLが
> http://www.studyinghttp.net/rfc_ja/2616/ に変更いたしました。
ご連絡ありがとうございます。修正いたしました。

>>2236 Ka23
> UNIX プログラミング FAQのサイトが
> http://www.adl.rd.nacsis.ac.jp/~moro/unix-programmer/faq-j_toc.html
> に移転しているようです。
こちらもありがとうございます。後ほど修正しておきます。


>>2243 sio
test.cgi は同じサーバにあるのですか? で、ブラウザから直接呼び出すこと
はないのですか? ならば CGI じゃなくてただのスクリプトですので、
main.cgi からは

    open(IN, "/foo/bar/test.cgi ID |");
と呼び出せばいいでしょう。ソケットを使う必要はありません。

もし test.cgi が同じサーバにあって、これまでは CGI として動いていたけ
ど、これからはブラウザから直接参照させたくない、ということならば、
    $ENV{REQUEST_METHOD}='GET';
    $ENV{QUERY_STRING}='data=1';
    open(IN, "/foo/bar/test.cgi |");
と、WWW サーバの代わりに適切な環境変数をセットしてからスクリプトを実行
してやればよいでしょう。


test.cgi が別サーバにあるならば、直接スクリプトを実行することはできな
いので、そのときはソケットを使いましょう。

> print SOCKET "POST $file HTTP/1.0\r\n";
> print SOCKET "Content-Length: $len" . "\r\n\r\n";
> print SOCKET "$query";
送ったはいいけど、これでは結果を受け取っていませんし、ブラウザに何も表
示していません。

      while (<SOCKET>){ # ヘッダを捨てる
          m/^\r\n$/ and last;
      }
      print "Content-type: text/html\n\n";
      while (<SOCKET>){ # ボディのみ表示
          print $_;
      }

とかいうのをこの後に付けて下さい。

> POSTについての情報がどこも少なく
あまり書くことがないからでしょう。気を付けるのはContent-length を付け
ること、くらいじゃないでしょうか。


あと、CGI 経由で HTTP クライアントを開発するのはやめましょう。まずはコ
マンドラインから動くような HTTP クライアントを作り、完成したら CGI 経
由でも動くように改造しましょう。でないと、問題の切り分けが非常に面倒に
なります。

No. 2247 # sio 2001/11/04 (日) 08:58:47
68userさんありがとうございます。
やりたい事が全てご指摘通りです(^^;

open関数のパイプの使い方すら知りませんでした。
今やっと説明されているページを見つけ
http://www.kt.rim.or.jp/~kbk/perl5.005/perlipc.html
勉強中です。

Socketについてもようやく理解できました。
データを受け取った側で、ブラウザ処理をしようとするから
訳が分からなくなっていたようです。

今日はperlに浸かり勉強する日にします p(..)

No. 2248 # 初心者 [E-mail] 2001/11/05 (月) 07:45:11
X Window Systemを立ち上げるときに、

(**) stands for supplied (--) stands for probed/default values
(**) ...
(**) ...

というメッセ-ジが出て立ち上げることができません。
これはいったいどういうことなのでしょうか。

No. 2249 # 初心者 [E-mail] 2001/11/05 (月) 08:06:53
正確には

(**) stands for supplied, (--) stands for probed/default values
(**) ...
(**) ...

でした。

No. 2250 # 68user 2001/11/05 (月) 10:26:23
>>2247 sio
> データを受け取った側で、ブラウザ処理をしようとするから
> 訳が分からなくなっていたようです。
まず、全体の構成を見直すべきでしょうね。
    - main.cgi に統合する。
    - test.cgi はユーザ名を引数で受け取り、ログイン可能なら
        戻り値 0 を、ログイン不可なら戻り値 1 を返す。
などと現在の仕様を比べ、一番良さそうなものを採用しましょう。

>>2249 初心者
> (**) stands for supplied, (--) stands for probed/default values
それは起動時に (成功・失敗にかかわらず) 必ず表示されるメッセージです。

また、OS などの環境が何も書いていないので、答えられる人は
いないでしょう。

# 僕は XFree86 やらビデオカードやらには詳しくないので、
# 書いてもらっても答えられないかもしれませんが。

No. 2251 # ミング [E-mail] 2001/11/07 (水) 18:42:55
こんにちは。いつもお世話になってます。

Perlについて質問があります。

各ファイルに ”ー1”と ”ー2”が含まれた行があって、それを区切りに2つのファイルに分けたいのですが、なかなかうまくいきません。

EXAMPLE:
*File0001の内容ーー

0001ー1

C100 Open
C101 NG

0001ー2

C102 Open
C103 Open

*File2の内容ーー

0002ー1

C200 Open
C201 NG
C202 Open

0002ー2

C203 Open
C204 NG

この0001と0002の2つのファイルを0001ー1と0001ー2、0002ー1と0002ー2の4つのファイルに分けたいのです。

下のスクリプトは全然間違ってるのですが、/-1/ と /-2/ があった行数を記憶して、後から 行の番号を比較してどうにか区切ろうと思ったのですが、やっぱり最初は$barcode22=0だし、全然駄目です。

普通、どのようにするのか教えて頂けませんか?

よろしくお願いします。

sub read_file_to_array { my($file)=$filename;
        
        open (FILE, "<$dir\\$database\\Defect\\$file") or die "Can't open $file\n";
          $line=0;
            while (<FILE>){
            
            if ($_ =~ /-1/) {$barcode11=$.};
            if ($_ =~ /-2/) {$barcode22=$.};
                                                          
            if ($line > $barcode22) {print "$_ ";}#試しにSTDOU#に出力してみるだけ
                                                            }
            $line++;
                                                    }

No. 2252 # ナナシサソ 2001/11/07 (水) 23:34:55
動くかわからんけどとりあえずできた

sub read_file_to_array { #←?
        my $file = shift;
        open (FILE, "<$dir\\$database\\Defect\\$file") or die "Can't open $file\n";
        open (OUT1, ">$dir\\$database\\Defect\\${file}_1") or die;
        open (OUT2, ">$dir\\$database\\Defect\\${file}_2") or die;
        my ($flag1, $flag2);
        while (<FILE>) {
                if ( /-1/ ) {
                        $flag1 = 1;
                }
                if ( /-2/ ) {
                        $flag2 = 1;
                        $flag1 = 0;
                }
                if ($flag2) {
                        print OUT2;
                        next;
                }
                if ($flag1) {
                        print OUT1;
                        next;
                }
        }
}

No. 2253 # ナナシサソ 2001/11/07 (水) 23:37:28
うぎょぎょ。。if ($flag2) {〜の部分の順番が逆になっちゃってるし。ダサ・・
closeしてないし・・終了時に閉じられるから大丈夫かアハハ

No. 2254 # 68user 2001/11/08 (木) 07:20:44
>>2251 ミング
必ずデータの先頭が .*-1 か .*-2 であるなら
    while (<FILE>) {
        if ( /-[12]/ ){
            chomp;
            open (OUT, ">$dir\\$database\\Defect\\$_") or die;
            next;
        }
        print OUT;
    }
かなぁと思うんですが、違うかな?

業務用プログラムかだとちゃんとエラーチェックしないとまずい
でしょうが、データの内容がある程度保証されているなら、こんな
テキトーな感じでよろしいかと思います。

No. 2255 # ミング [E-mail] 2001/11/08 (木) 14:47:58
ナナシサソさん、68userさん

出来ました!!
ご指導どうもありがとうございました。

No. 2256 # ミング [E-mail] 2001/11/08 (木) 17:54:35
二日連続の質問になってしまいますが、よろしくお願いします。

No.2251のInput file名は"Ab00010", "Cd00020", のように文字と数字からなっているのですが、Outputは別のDirに"Ab00010" "Ab00011" "Cd00020" "Cd00021"というように、/-2/の部分は”元のファイル名+1”というファイル名にしたいのですが、、、、

800ページあるらくだの本も一応買ってきたのですが全然分からないので、ウェブサイトで調べてみたのですが、唯一これかな?と思ったのが:

$string="abcd771gfds";
$string=~/(\W+)\s+(\d+)/;

とすると、$1=abcd, $2=7771, $string=abcd771gfds になる、とあったんですが、

試してみると$1=" ", $2=" ", $string="4294967295"になってしまい、訳が分からなくなってきたのですが、これは全然違うアプローチなんでしょうか?

どうしたら ”Ab00011”が作れるんでしょうか?

No. 2257 # ナナシサソ 2001/11/09 (金) 00:10:23
$flag == 2 ? $string ++ : ;
でいいと思う・・ゲロゲロ

No. 2258 # オハツ [E-mail] 2001/11/09 (金) 12:52:13
UNIXの歴史について、知ってる範囲で教えてください。
できれば、メールの方がありがたいです。

No. 2259 # ミング [E-mail] 2001/11/09 (金) 14:36:01
>>2257 ナナシサソ
でもアルファベットと数字からなってるので、数字だと見てくれないみたいなんですけど、、、

No. 2260 # ナナシサソ 2001/11/09 (金) 23:11:03
>>2259 ミング
Perlは妙なことが出来たり・・
多分うまくいくと思うんだけどな・・

No. 2261 # ふくし [E-mail] 2001/11/10 (土) 18:48:47
ミングさんはじめまして。
まず abcd771gfds の件です。

#!/usr/bin/perl

$string = "abcd771gfds";
$string =~ /(\W+)\s+(\d+)/;

print "1:<$1> 2:<$2> string:<$string>\n";

を動かすと

1:<> 2:<> string:<abcd771gfds>

と出ました。

\W+ は、英数字(word)以外1文字以上なので、なくてあたりまえ。
\s+ は、空白文字(space)1文字以上なので、なくてあたりまえ。
\d+ は、数字(digit)1文字以上だが、前に \W も \s もないのでダメ。

もし、$1 に abcd、$2 に 771(7771 は間違い?)を入れようとするなら、

$string =~ /^([a-zA-Z])(\d+)/;

とかでしょうか。
^ は文字列の先頭を示します。
これをやらないとどこからサーチしはじめるかわからん。
[a-zA-Z] は英字。\d は数字。
(わー、目からウロコ。英字のカンタンな文字クラスってないんですね)

#!/usr/local/bin/perl

$string = "abcd771gfds";
$string =~ /^([a-zA-Z]+)(\d+)/;

print "1:<$1> 2:<$2> string:<$string>\n";

を動かすと

1:<abcd> 2:<771> string:<abcd771gfds>

となりました。

No. 2262 # ふくし [E-mail] 2001/11/10 (土) 19:01:48
ミングさん、つぎにファイル名生成の件です。
もっとカッコいいプログラムはいくらでもあるかと思うんですが、
ここではわかりやすく確実に動くのを取りました。

#!/usr/bin/perl

$fname = "Ab00010";

$fname =~ /([a-zA-Z]+)(\d+)/;
$fname_a = $1; # 英字部分
$fname_n = $2; # 数字部分

$fname_n++; # 数字部分に1加算
$fname_n = sprintf "%05d", $fname_n; # 先頭にゼロを詰めて5文字に
$fname = $fname_a.$fname_n;
print "fname: $fname\n";

$fname_n++; # 数字部分に1加算
$fname_n = sprintf "%05d", $fname_n; # 先頭にゼロを詰めて5文字に
$fname = $fname_a.$fname_n;
print "fname: $fname\n";

$fname_n++; # 数字部分に1加算
$fname_n = sprintf "%05d", $fname_n; # 先頭にゼロを詰めて5文字に
$fname = $fname_a.$fname_n;
print "fname: $fname\n";

実行してみます。

fname: Ab00011
fname: Ab00012
fname: Ab00013

ポイントは sprintf でしょうか。
これは文字列をいろんな形で整形しますが、汎用性が高すぎるので、

    sprintf "%0n", m;
        n はケタ数、m は数字

で、m を n ケタ、ゼロ詰めで表示するとだけ今はご説明します。

ただですね、これだと1ファイルが10個以上のサブファイルに分けると
Ab0002n に突入してしまって、
もし Ab00020 という元ファイルがあると名前が衝突しますが、
それはいいですか。

No. 2263 # 68user 2001/11/11 (日) 18:45:38
>>2258 オハツ
> UNIXの歴史について、知ってる範囲で教えてください。
「UNIXの1/4世紀」
        http://www.ascii.co.jp/books/detail/4-7561/4-7561-3659-1.html
を読みましょう。

No. 2264 # ミング [E-mail] 2001/11/12 (月) 13:51:26
ふくしさん、ナナシサソさん、

ご教授どうもありがとうがざいました。 やっと出来ました。
とても分かり易く助かりました。

今後もいろいろと宜しくお願いいたします!

No. 2265 # 武田一浩 2001/11/14 (水) 15:57:05
    はじめまして。教えていただきたいことがあります。
    こちらを参考に、perlのネットワークプログラムを作りたいと思っています。OSはPlamo Linux、perlは5.005です。

    やりたいのはローカルネットワーク上に、ブロードキャストでメッセージを送って、ポートを開いている全部のコンピュータがそのメッセージを受信するというものです。
    試験として

#!/usr/local/bin/perl

use IO::Socket;

$socket = IO::Socket::INET->new(
        PeerAddr => '192.168.0.255',
        PeerPort => 2425,
        Proto => 'udp',
        );

if ( ! $socket ){
        die "接続できませんでした。 $!\n";
}

        print $socket "test";
        $socket->flush();


$socket->close();

    と、いうのを動かしてみました。ブロードキャストである192.168.0.255ですから、2425でポートを開いている他のPC(VBのwinsockを使いました)にtestが表示されるかと思ったのですが、

> 接続できませんでした。 不正なファイルデスクリプタです

というエラーが返って来てしまいます。
このエラー、192.268.0.3の様にIPを指定すると、出現しません。

    いろいろとサーチエンジンなどもあたったのですが、どうしてもこの原因がつかめず、困っています。
    perlを使って、udpとブロードキャストアドレスでネットワーク通信されている方がいらしたら、ブロードキャストアドレスをどうやって指定しているか、教えていただけませんでしょうか?
    よろしくお願いいたします。

Prev< No. 2239〜2265> Next  [最新発言に戻る] [過去ログ一覧]