• ベストアンサー

[Perl] Pack関数について教えてください。

こんにちは。 下記は、pack関数のサンプルスクリプトですが、 なんでそのような結果になるのか、よくわかりません。どなたか教えていただけますか。 print "文字列を入力してください:"; $string = <STDIN>; chomp ($string); $length = length($string); print "数値を入力してください:"; $number = <STDIN>; chomp ($number); # Do Pack! $packed = pack("A${length}i", $string, $number); print "パック文字列: $packed\n"; --- 結果 --- 文字列を入力してください:perl 数値を入力してください:100 パック文字列: perl

  • Perl
  • 回答数2
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • hofuhofu
  • ベストアンサー率70% (336/476)
回答No.2

Packは複数の変数をひとつにまとめるためのものですね。 書式としては Pack(テンプレート,変数,変数,......) となります。 今回の場合はテンプレートは、 A${length}i ですが、$lengthには$stringの長さですから、$string=perlなら4になるので、 A${length}i = A4i ですね。 A{n}はn文字分の領域を確保するという意味なので、A4なら4文字分の領域が確保され、そこにperlという文字列が格納されます。 もしこれがA6とかでperlという文字列を格納しようとすると、2文字分余るので余った部分にはスペースが入れられます。 'p','e','r','l'のアスキーコードはそれぞれ16進数で70,65,72,6Cなので$packedには 70 65 72 6C といった情報が格納されます。 次にiですが、これは32ビット以上の符号付整数型となっています。 PCでperlを動かしているなら、ほとんどが32ビット環境となっていると思うので、これは事実上32ビットと思ってください。 100は16進数であらわすと64ですが、これが32ビット=4バイト整数型に格納されたとすると00000064(0を増やして4バイト分の情報にしているだけ)といった感じになります。 さらにこれがメモリなどに格納される場合には1バイト単位で分解されるわけですが、ビッグエンディアンと呼ばれる形式で格納された場合には順番が反転して、 64 00 00 00 となります。 http://www.atmarkit.co.jp/icd/root/70/5784470.html A4iでこの二つのデータが結合されますから、結果としては 70 65 72 6C 64 00 00 00 となり、これをprintで表示すると、アスキーコードにしたがって、 perld となります。 後ろの3つの00はNULL文字なので見えません。 ちなみに符号有り、符号無しというのは負の値を使うか、使わないかということです。 たとえば1バイトで表現できるのは256個の数字ですが、符号ありの場合は-128~127の値を、符号無しの場合は0~255の値を表すことができます。

cgi_syoho
質問者

お礼

大変親切かつ丁寧にご説明いただき、どうもありがとうございます。 目からウロコのような解説です。 ぼくだけでなく、ぼくと同じ疑問を抱いているかも知れない人たちにもぜひ詳細したいくらい、大変よく理解できました。 もしよろしければ、今後も教えていただけたらと思います。 本当にどうもありがとうございます。

その他の回答 (1)

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.1

実行結果って、 パック文字列: perld ――じゃありませんか? もしそうなってないなら、表示が崩れているだけでは。 そういう話じゃなくて、「そもそもpackって何?」という話だとしたら、メモリへの値の直接書き込んでいるイメージがわかないと、ピンとこないかも。

cgi_syoho
質問者

補足

こんにちは。この度はどうもありがとうございます。 ご指摘とおり、実行結果は、「perld」です。 すみませんでした。 そうですね、。。「そもそもpackって何?」ってところが理解できてないんだと思います。 参考書には、「符号無しのchar型」など説明されていますが、ピンとこないのが正直なところですね。 よろしかったら、「packって何をするためのもの?」について教えていただけたら嬉しいです。 よろしくお願いいたします。

関連するQ&A

  • perlの「until」ループ文

    こんにちは。以下のループ文ですが、 --- print "初期値を入力してください:\n"; $number = <STDIN>; chomp($number); until ($number > 16) { print "数値:$number\n"; $number += $number; } --- 実行画面で「2」を入力すると、 数値:2 数値:4 数値:8 数値:16 のように出力されます。 なぜでしょうか?2,3,4....16じゃないの? どなたか、教えてください。よろしくお願いします。

    • ベストアンサー
    • Perl
  • Perlのプログラミングについて

    Perlのプログラミングでつまづきました。 # ファイルから指定文字列を含む行を収集する # 入力ファイルのオープンと読み込み print( "入力ファイル名?" ); $n = <STDIN>; chomp( $n ); open( FIN, "<$n" ) or die "入力ファイルオープンエラー: $!\n"; $n = @a = <FIN>; close( FIN ); print( "$n 行読み込みました\n" ); # 行の収集 print( "検索文字列?" ); $x = <STDIN>; chomp( $x ); $ptn = $x; #指定の文字列 $x = @b = grep( /$ptn/, @a ); print( "$x 行見つかりました\n" ); # 出力ファイルのオープンと書き出し print( "出力ファイル名?" ); $y = <STDIN>; chomp( $y ); open( FOUT, ">$y" ) or die "出力ファイルオープンエラー: $!\n"; print FOUT ( $ptn, "\n" ); print FOUT ( $x, "\n" ); print FOUT ( @b ); close( FOUT ); というプログラムで実行すると C:\My Perl\pl>perl プログラムの実行.pl 入力ファイル名?sample1.txt 168 行読み込みました 検索文字列?k 45 行見つかりました 出力ファイル名?out3-24.txt 続行するには何かキーを押してください . . . となり出力ファイルの中身が表示されません。 どこを間違えているのかご指摘いただけないでしょうか?

  • perlの正規表現

    はじめまして現在Perlでスクリプトを作成しています。 やりたいことは ・ユーザがコマンドラインより文字(ユーザID)を入力 ・その文字列が#getent passwdの結果にあるか無いかで処理を分ける です。 #getent passwd | grep hogehogeの結果は下記のとおりです。 hogehoge:x:1210:104:staff:/home/data/staff/hogehoge:/bin/bash これより先頭の[hogehoge]とユーザが入力したhogehogeが完全一致すれば問題ありません。 正規表現を調べましたが文字列での一致はあるのですが引数での文字列が調べることが出来ませんでした。 よろしくお願いします。 print "Enter User ID\n"; $id = <STDIN>; chomp($id); $cmd =`getent passwd | grep $id`; system($cmd); if ($cmd == ~ /^$id/) { print "There is not ID\n"; } else { print "Your ID is there\n"; }

  • Perlで数が正しくファイルに読み書き出せません

    Perlで、下のように300の数を読み書きしたところ、 10、26、266、282 だけ正しく読み出せません。なぜですか? open (FRED,"+<test"); $pack_format = "I"; $pack_length=length pack($pack_format,0); for ($n=0;$n<300;$n++){ $age=$n; seek(FRED,$pack_length*$n,0); print FRED pack($pack_format,$age); } for ($n=0;$n<300;$n++){ seek(FRED,$pack_length*$n,0); $qqq=read (FRED,$buf,$pack_length); $age=unpack $pack_format,$buf; print "/$n/$age/$qqq/\n"; }

    • ベストアンサー
    • Perl
  • perlでのSTDINについて

    最近、perlを独学で勉強し始めたものです。 1行で複数回データの入力を行いたいのですが、データを入力するたびに改行されてしまいます。 今は$変数=<STDIN>としているのですが、STDINで取得したデータには\nが含まれているようなので、chompを使うのかと考えているのですがどうしたらいいのか分かりません。それとも何か別の方法があるのでしょうか?

    • ベストアンサー
    • Perl
  • Windows 用 Emacs で、shell で困ってます

    perl のプログラムを、Emacs の shell で実行すると,打ったコマンドが、次の行に現れて、プログラムがうまく動いてくれません。たとえば、 print "Enter a first number: "; chomp($one = <STDIN>); の部分が、プリントされないのです。何も表示されてないところへ、数を入力すると、最後にまとめてプリントされます。  Emacs をカスタマイズすれば直るものでしたら、嬉しいんですが。  ちなみに、perl は、Active Perl です。 どなたか、わかる方がおられましたら、ご教示願います。

  • PHPのpack関数をJavaで実装できるのでしょうか

    PHPで文字列を16進バイナリ文字列に変換する関数であるpack関数というものがありますが、これと全く同じ動きをしてくれるメソッドがjavaには存在しないようです。これを自分で実装する方法をあれこれ考えているのですが、どうしてもうまくいきません。 下のようなメソッドを作ってみたのですが、戻ってくるのはただの数値文字列です。 /** * @param toPack バイナリへの変換対象の数値 */ String getHexBinary(int toPack){ String buf = ""; String hex = Integer.toString(toPack, 16); char decChars[] = hex.toCharArray(); for(int decChar : decChars){ buf += Integer.toHexString(decChar); } return buf; } PHPのpack関数はこの戻ってくる数値文字列を何らかの手法で結合しているように見えるのですが、その挙動が理解できずに困っています。どなたか、ご教授願えないでしょうか。ちなみに、Javaのバージョンは5.0でやっています。PHPのバージョンは5.2です。

    • ベストアンサー
    • Java
  • perlがうごきません

    <html> <head> <title>form3</title> </head> <body> <form action="form3.cgi" method="post" name="form3"> <input type="text"name="form3"> <input type="submit"value="送信"> </form> </body> </html> ::::::::::::::::::::::::::::::: #! /usr/bin/perl if($ENV{"REQUEST_METHOD"} eq "GET"){ $str=$ENV{QUERY_STRING"}; }else{ read(STDIN, $str, $ENV{"CONTENT_LENGTH"}); } $str=~ tr/+/ /; $str=~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("c", hex($1))/eg; foreach(split(/&/, $str)){ my ($key, $value)=split(/=/, $_); $data{$key}=$value; } print "Content-type:text/html\n"; print "\n"; print "<html>\n"; print "<head><title>form3</title></head>\n"; print "<body>$data{'form3'}</body>\n"; print "</html>\n"; exit; :::::::::::::::::::::::::::::::: どうしてもうごきません。 どこかスクリプトがまちがっているのでしょうか。 パールのパスはあっています。

    • ベストアンサー
    • Perl
  • 文字列比較

    最長10文字の文字列を2件入力し、char型の配列にそれぞれ格納する。2つの文字列を比較し、文字列が同じだったら「equal」を表示し異なっていたら「Not equal」を表示するプログラムを作成せよという課題が出ました。 条件として、11文字以上の文字が入力されたら、先頭から10文字までを有効とし、11文字目以降を無視する。下記のプログラムで文字列1に11文字以上入力すると、うまく動きません。なぜ、うまくいかないかと、どうなおしたらよいかを教えてください。 #include<stdio.h> #include<string.h> #define max_length 10 void get_string (char *p_str, int size); int main() { char string1[max_length+2]; char string2[max_length+2]; printf("文字列1:"); get_string(string1,max_length+2); printf("文字列2:"); get_string(string2,max_length+2); if(!strncmp(string1,string2,max_length)) puts("equal"); else puts("Not equal"); } void get_string (char *p_str, int size) { fgets(p_str,size,stdin); }

  • Perlの正規表現

    Perlの正規表現である文字列に文字列STRINGが含まれないようにするには ^(?!.*STRING).+$ と書くとググったら出てきました. ですが,?!について詳しいことまで書いてるサイトはありませんでした. ?!は具体的にはどのようなことをするのでしょうか?

専門家に質問してみよう