Perl

2009年2月24日 (火)

「すぐわかるPerl」 8.10 ディレクトリのリカーシブ処理(その2)

■ワードカウントさせてみよう

「すぐわかるPerl」 8.10 ディレクトリのリカーシブ処理(その1)でやったtreeにワードカウント機能をつけてみる。(ただし、半角で区切りを判断するので、英語用かな)

  • $depをグローバル変数にして使ってみる。(現在いる階層の深さ)
  • $awcという変数を全ワードカウントの累計につかう。
  • -Tはテキストファイルの場合に真になるファイルチェック演算子
  • -Bはバイナリファイルの場合に真になるファイルチェック演算子
  • ワードカウントの方法は、wcコマンドの出力を空白でsplitした3番目の要素を使う
  • $dwcにはディレクトリごとのワード数を累計する

#! /usr/local/bin/perl

# tree .. カレントディレクトリ以降のファイルリストを作成
# ワードカウントもあるよ

$dir = 'pwd';
print $dir;
$dep =1;
$awc = 0;
&dirproc;
if ($awc > 0){
print "\n*** this directory has $awc words test files in total.\n";
}

sub dirproc {
my(@files , $file , $dwc);
@files = sort(glob("*"));
foreach $file(@files) {
  if (-T $file){
   @t=split(/\s+/,`wc $file`);
   for ($i = 1; $i <= $dep; $i++){
    print "|\t";
   }
   print $file."\t".$t[2]."\n";
   $dwc += $t[2];
   $awc += $t[2];
  }
}

if ($dwc > 0){
  for ($i = 1; $i <= $dep; $i++){
  print "|\t"
  }

  print "\n*** this directory has $dwc words test files in total.\n";
}

foreach $file(@files) {
  if (-B $files and -f $file){
   for ($i =1; $i <= $dep; $i++){
    print "|\t";
   }
   print $file."\n";
  }
}

foreach $file(@files) {
  if (-d $file){
   for ($i = 1; $i <= $dep; $i++){
    print "|\t";
   }
   print $file."\n";
   ++$dep;
   chdir($file);
   &dirproc;
   chdir(".." or die "waaaa");
   --$dep;
  }
}
}

| | コメント (0) | トラックバック (0)

2009年2月23日 (月)

「すぐわかるPerl」 8.10 ディレクトリのリカーシブ処理(その1)

■リカーシブ処理とは
猿が玉ねぎの皮を無限に向いて行くようにどんどんディレクトリを掘って深く処理することをリカーシブ(recursive)処理とか再帰的処理という。

rm に -R のスイッチを渡すと、rmはリカーシブにそのディレクトリ以降のうファイルまたはディレクトリをすべて削除する。

このような処理をする場合にはリカーシブコールができると楽。
リカーシブコールとは、あるサブルーチンの中からそのサブルーチンを呼び出すこと。

概念をプログラム風日本語で書く
このように自然言語でプログラムを書くことを疑似コーディング(スードコーディング:pseudo cording)という。

メイン:
「ディレクトリごとの処理」を呼び出す。

「ディレクトリごとの処理」サブルーチン:
そこにあるファイルに対してファイルごとの処理を行うことを、
ファイルがある限り繰り返す。

そこにあるディレクトリすべてに対して、いかの処理を繰り返す{
  そのディレクトリに入る   # cd そのディレクトリ
  「ディレクトリごとの処理」を呼び出す #ここがリカーシブ
  もとのディレクトリに戻る  # cd ../
}
}

これで全ディレクトリに対してリカーシブに処理が進む。

■ディレクトリ構造をtreeコマンドで表示させる
・Windows NTのDOS窓にあって、95とUNIXにないのがtreeコマンド
・perlでtreeコマンドを作ってみる。

●ローカル変数を定義する
メイン処理

$dir = `pwd`; #pwdコマンドを実行して、その結果を$dirに入力
print $dir; #$dirを表示
$dep =1; #自分のいる階層の深さを1で初期化
&dirproc($dep); #サブルーチン&dirprocに$depを渡してサブルーチン処理へ

引き続き。

sub dirproc {
my($dep) = @_;
my(@files,$file);

まず、myによってサブルーチン内でのみ通用する変数を定義する。
このような変数はローカル変数と言われる。
コレよにって、サブルーチンの外側で同じ名前の変数が利用されても、それらの変数とは衝突(conflict)しない。
コレを別の名前空間、またはネームスペース(name space)をもつと言う。

ローカル変数を利用する利点は、
1.衝突を防げるという、保険的意味合い
2.汎用性(サブルーチンのコードをそのまま流用できる)

なお、プログラム全体で利用できる変数はグローバル変数と言われる。

ただし、自分を再帰的に呼ぶ場合には変数をローカル変数にしないと動かない。
理由は「自分」自身で「自分」を呼び出す、という処理をするため。

dirprocは呼びだされると my キーワードによって、新しいネームスペースに変数 $files と @files を用意する。
これが新しい階層ごとに行われ、変数名が同じであっても、新しいネームスペースに存在するためにぶつかることはない。

●ファイルごとの処理

@files = sort(glob("*"));

ファイル名グロブ (glob("*")); はリストコンテキストで全ファイル/ディレクトリを返す。
それを辞書順でsortしたものを配列@filesに入れる。globについては195p。引用。

リストコンテキストでは、globはファイル名パターンにマッチするファイルの全ファイル名を一気に返します

ファイル名パターンが「*」だから、全ファイルなわけだな。

foreach $file(@files) {
if (-f $file){
  for ($i = 1; $i <= $dep; $i++){
   print "|\t";
   }
   print $file."\n";
  }
}

ここで、

@filesをなめて、$fileに入れ、操作します

とあるけどなめる?イメージできん・・・

if (-f $file){

ここで出てくる -f はファイルチェック演算子というものの一種で、右に来る文字列の中身をファイル名として吟味する。

-f はファイルの略で、右に来るものが存在し、かつ、普通のファイルであれば真を返す。

ファイル名の表示の前には、階層の深さに応じて、|(縦バー)、プラス、タブ文字が入る。

●ディレクトリ単位の処理

foreach $file(@files) {

if (-d $file){

  for ($i = 1; $i <= $dep; $i++){
   print "|\t";
  }

  print $file."\n";
   chdir($file);
   ++$dep;
   &dirproc($dep);
   chdir("..") or die "abend. don&apos;t ask me why";
   --$dep;
}
}

ここでは、ファイルチェック演算子 -d を用いる。
ディレクトリ名が右に来た場合には真を返す。

「縦バー + タブ + $file」の表示は先ほどの処理と同じ。

続いて、chdir 関数を呼び出す。chdirについてはUNIXのコマンドと同じ。
chdir には $files をわたす。この時点では$filesにはディレクトリが入っている。
コレにより、一つ下の階層に移動する。
ここで、階層の数が増えるので、 $dep をインクリメントする。
そして、サブルーチン &dirproc を呼び出す。
処理が終わったら帰ってきたら $depをデクリメントする。

| | コメント (0) | トラックバック (0)

2008年11月12日 (水)

「すぐわかるPerl」 8.9 コマンドの入出力に入出力を切り替える

UNIXで言うところの|(パイプ)はどう扱うか?

open(ファイルハンドル名 , " | コマンド名")

でそれ以降の「printファイルハンドル」が発行されるごとに、printの出力がそのコマンドに対する入力となり、そのファイルハンドルをクローズするとそのコマンドが実行されます。

ただし、コマンドはパイプラインで使えるもの、つまり標準入力から受け付けられるものに限る。

メールを送るmailコマンド

# oshirase
open (ENKAI , "| mail enkai\@speed.org")
print ENKAI "Enkai no oshirase!\n";
print ENKAI "1999/9/9 nichi!\n";
print ENKAI "wasureruna!\n";
close(ENKAI);

@の前に\をつけたのは、二重引用符の中に@を核と、Perlが配列変数と思ってそれを展開してしまうから。
実行することで、メーリングリストenklai@speed.orgのメンバーにメールが届く。

入力モードでも|を利用することができる。
unixのwhoといういコマンドはunixにログインしている人の一覧を表示できるが、これをsortしてuniqして表示する場合。

※ who |sort |uniq でよくね?とおもったら・・・

ただし、whoで表示される名前とログイン日時、端末情報のうち名前だけを取り出してsortしてuniqする。

むぅ。

# wholist

open(WHO,"who |"); #ファイルハンドルWHOがwhoコマンドの出力に結びつく

while(<WHO>) {  #以降<WHO>をスカラーコンテキスト(配列の要素数)で
   #評価するごとにwhoの出力を返す。

($one)=split; #$_を空白文字でsplitしたものの配列を1要素のリストに
   #リストコンテキストで渡す。
   #つまり、whoで出た名前の部分だけを$oneに入れる。

push(@who,$one);#@whoの一番右側(インデックスの値が一番大きい要素)に
   #$oneを追加する。
   #push(@配列名 , スカラー)
   #で配列の末尾にスカラーが追加される。
   #@配列名 = (@配列名,スカラー)
   #と書くのと同じ。
}
close(WHO);

open (KEKKA, "| sort | uniq");
   #重複をなくし、sortする。
   #openされたKEKKAに@whoをそのまま(改行つけて)
   #出せば出力がsortされ、uniqされて画面に出てくる。
foreach(@who){
print KEKKA "$_\n";
}
close(KEKKA);

#後半がわからんな・・・
 @whoがどうKEKKAに渡されるのかが・・・どこで渡されんだ?

■標準入出力以外のアクセスのまとめ

<STDIN>,<STDOUT>以外ってことで。
このあたり、よくわからないなぁ・・・

・ファイルの入力オープン
open (ファイルハンドル名 , "物理ファイル名")

・コマンドからの入力オープン
open (ファイルハンドル名 , "コマンド名")

・入力
<ファイルハンドル名>

・ファイルの出力オープン
open (ファイルハンドル名 , "> 物理ファイル名")

・ファイルの追加書きオープン
open (ファイルハンドル名 , ">> 物理ファイル名")

・コマンドへの出力オープン
open (ファイルハンドル名 , "| 物理ファイル名")

・出力
print ファイルハンドル名 スカラー

・出力ハンドルの切り替え
select (ファイルハンドル名)

・ファイルのクローズ
close(ファイルハンドル名)

| | コメント (0) | トラックバック (0)

2008年10月 8日 (水)

「すぐわかるPerl」 8.8 標準入出力以外のファイルの制御

ファイルへの出力

一つのプログラムの中でファイル名パターンによる検索、そのファイルの入力、そして別ファイルへの出力をやってしまいたい場合。

#repampsub -- ワイルドカードを渡して ampsub

$argn = ($oldext , $newext) = @ARGV;
($argn == 2) or &bye("argument must be two\n");

@files = glob("*$oldext");
(@files + 0) or &bye("extention \"$oldext\" no match\n");

foreach (@files){
/(.*)\.$oldext/;
open (IN, "$1.$oldext");
open (OUT, ">$1.$newext");
while (<IN>) {
  s/$#169;/&copy;/g;
  print OUT;
}
}

close IN;
close OUT;

sub bye{
my($msg) = @_;
print $msg;
die "usage: repampsub old_extention new_extention\n";

}

以下解説

「1個目のopen命令において、"$1.$oldext"という物理ファイル名がINというファイルハンドル名に入力モードで結びつけられる。」
・・・ごめん、何言ってんだか全然わかんない・・・
INというのは任意でつけた名前らしい。

/(.*)\.$oldext/;
open (IN, "$1.$oldext");
open (OUT, ">$1.$newext");

わからないけど、止まっても永遠に理解できそうにないので先に進む。

2個目のopen命令では"$1.$newext"という物理ファイル名がoutというファイルハンドル名に出力モードで結びつけられる。

・・・OUTというのは任意で決めた名前らしい。

入力モードで結びつけられる、とか出力モードで結びつけられるってのがよくわからん。

STDINはオープンの必要のない入力のファイルハンドル
STDOUTはオープンの必要のない出力のファイルハンドル

ってことは、STDINとSTDOUT以外はopen命令が必要なのか。

つか、open命令とか急に言われてもなー

while (<IN>) {
  s/$#169;/&copy;/g;
  print OUT;
}

ここで<IN>は標準入力に対する<STDIN>同様、ファイルハンドルINに結びつけられた物理ファイルから1行読んでその値を返す。
このとき、ファイルポインタがインクリメントされる(次の値を読みに行くってこと?)
ファイルポインタが再就業を指したときさらに<IN>を評価すると、<IN>はundefを返す。
while文がfalseとなり、ループが終わる。

■OUTへの出力

引き続き。
したの置換部分は実態参照の著作権マークを読みやすく変えるもの。

while (<IN>) {
  s/$#169;/&copy;/g;
  print OUT;
}

次のprintは従来のprintと基本的に同じですが、標準出力に出す代わりにOUTと結びつけられた物理ファイルに出力する。

print ファイルハンドル名, 文字列 ;

ファイルハンドル名を省略したとき:STDOUT
文字列を省略したとき:@_

となる。

OUTへの出力を何回も行う場合は、デフォルトのファイルハンドルをSTDOUTからOUTに切り替えると便利。
この場合、

select (OUT);

のようにファイルハンドルを切り替えると、それ以降持続的にデフォルトのファイルハンドルが切り替わる。
後でまたSTDOUTに出力したいときには

print STDOUT;

のようにprintでわざわざ(明示的に)STDOUTを指定するか

select(STDOUT);

のようにファイルハンドルを再切換えします。

最後に、INとOUTをクローズする。

close IN;
close OUT;

なお、同じファイルハンドルに対してopeを複数回行うと、二回目以降はcloseしてからopenしてくれる。

また、> のかわりに >>を出力すると、追加書きモードになる(append)。

| | コメント (0) | トラックバック (0)

2008年10月 7日 (火)

「すぐわかるPerl」 8.7 制御構造としてのand,or

■制御構造としてのand,or
8.6で書いた

unless ($argn == 3){
die "argument must be three\n".
  "usage : rep filter old_extention new_extention\n";
}

の部分は次のように書き換えることができる

($argn == 3) or die "argument must be three\n".
  "usage : rep filter old_extention new_extention\n";
}

説明

or というのはその前の式を評価して、「そこで真だったら、その後に結合しているものを飛ばして先に行く」という性質を持っている。
この場合には「$argn」が真であれば、その後のdieを飛ばして先に進む。

一方、条件が偽だったら、orの後ろにある文を評価しに行く。この場合にはdieでプログラム自体が止まる。

これは、条件式を評価するorが、制御文として使えることを示している。
「プログラム言語として読むとその内容は自明ではないが、自然言語として読むとよくわかる」

dont move, or die:動いたら殺すぞ(うごくな、さもなくば死か)

のように、

($argn == 3) or die :$argnが3で無ければdie

と解釈。
エラーチェックなどによく使われる。

同様に

if (`which $filter` =~ /^no /){
die "filter \"$filter\" not found\n".
"usage :rep filter old_extention new_extention\n";
}

(`which $filter` =~ /^no /)  and die "filter \"$filter\" not found\n".
"usage :rep filter old_extention new_extention\n";

と書くことができる。
and は or とは逆に左側に書いてあるものが偽であったら、その時点で右側の文をあきらめて先に進む。
(条件が正しければ、右側の文を評価する)

以上を踏まえ、プログラムrepは以下のように記述することができる。

$argn = ($filter,$oldext,$newext) = @ARGV; #@argvは引数が入る関数

($argn == 3) or die "argument must be three\n".
"usage : rep filter old_extention new_extention\n";

@files = glob("*.$oldext"); #oldextに該当する拡張子を持つファイル名を配列として@filesに格納

(@files + 0 ) or die "extention \"$oldext \" no match\n;.
"usage: rep filter old_extention new_extention\n";

(`which $filter` =~ /^no /)and die "filter \"$filter\" not found\n".
"usage :rep filter old_extention new_extention\n";

foreach(@files){
/(.*)\.$oldext/;
print("$filter < $1.$oldext > $1.$newext &\n");
system("$filter < $1.$oldext > $1.$newext &");
}

■サブルーチンの活用

dieのときに「usage」(使用法)を3回も連呼している。
このusageの呼び出しをサブルーチンにする。

$argn = ($filter,$oldext,$newext) = @ARGV; #@argvは引数が入る関数
($argn == 3) or &bye("argument must be three\n"); #$argnが3であれば以降は無視

@files = glob("*.$oldext"); #oldextに該当する拡張子を持つファイル名を配列として@filesに格納
(@files + 0 ) or &bye ("extention \"$oldext \" no match\n); #@filesが0であれば、以降は無視。

(`which $filter` =~ /^no /) and &bye ("filter \"$filter\" not found\n"); #fileterがない場合
       #(`which $filter` =~ /^no /)が真なら以降を実施。

foreach(@files){     #oldextの拡張子を持つものがあれば以降を実施
/(.*)\.$oldext/;    #正規表現でoldextの拡張子を持つもの
system("$filter < $1.$oldext > $1.$newext &"); #
}

sub bye{
my($msg) = @_;
print $msg;
die "usage :rep filter old_extention new_extention\n";"
}

| | コメント (0) | トラックバック (0)

2008年9月22日 (月)

「すぐわかるPerl」 8.5 エラーチェックを入念に 8.6 バッククォートでコマンドの結果を知る

$argn = ($filter,$oldext,$newext) = @ARGV; #引数を1個目から$filter,$oldext,$newext に格納

unless ($argn == 3){   # @ARGVをスカラーコンテキストで評価した
     # 時に3ではない場合、下のテキストを吐いて止まる。
die "argument must be three\n".
  "usage : rep filter old_extention new_extention\n";
}

@files = glob("*.$oldext"); #oldextに該当する拡張子を持つファイルを@filesに格納

unless (@files + 0 ){
die "extention \"$oldext \" no match\n;.
"usage: rep filter old_extention new_extention\n";
}

if (`which $filter` =~ /^no /){  # `(バッククォート)でUNIXコマンドを囲むと
     # そのコマンドが実行され、標準出力に出力される文字列が
     # 値として返る。
     # $a=`コマンド` だとコマンドの結果がすべて$aに入る
     # @a=`コマンド` だとコマンドの結果が1行1要素に入る

die "filter \"$filter\" not found\n".
"usage :rep filter old_extention new_extention\n";
}

foreach(@files){
/(.*)\.$oldext/;
print("$filter < $1.$oldext > $1.$newext &\n");
system("$filter < $1.$oldext > $1.$newext &");
}

| | コメント (0) | トラックバック (0)

2008年9月12日 (金)

8.4 ディレクトリ内のファイル連続処理

今までの知識を使ってrep(ディレクトリ内のファイルの拡張子を変える)を作る。

($filter,$oldext,$newext) = @ARGV; #引数を1個目から$filter,$oldext,$newext に格納

@files = glob("*.$oldext"); #oldextに該当する拡張子を持つファイルを@filesに格納

foreach(@files){
/(.*)\.$oldext/;
system("$filter < $1.$oldext > $1.$newext &");
}

# @filesにたまったファイル名の拡張子を取り除いた部分を$1に入れ、コマンド
# $filter < $1.$oldext > $1.$newext
# を実行。
# 末尾に & を付与してUNIXのバックグラウンドで実行。

| | コメント (0) | トラックバック (0)

2008年9月 8日 (月)

「すぐわかるPerl」 8.3 systemコマンド

8.3 systemコマンド

プログラムからUNIXのコマンドを呼び出す方法

system(コマンド文字列);

こでで、mの事列で指定したコマンドを実行し、戻り値を返す。

カレントディレクトリ内の全ファイルの削除

system("rm *");

このプログラムを以下のように実行することと

下記のコマンドは同じ。

rm *

危険なので試さないこと!

| | コメント (0) | トラックバック (0)

2008年9月 3日 (水)

「すぐわかるPerl」 8.2 ファイル名グロブ(glob)

シェルのファイル名パターンを使って、ファイルの一覧をゲットする機能。
・・・えっと、「ファイルの一覧をゲット」、これはわかる。
でもシェルの「ファイル名パターンを使って」ここがわからん。

まぁいいや。
先に進む。

書き方1:<ファイル名パターン>
書き方2:glob(ファイル名パターン)

アンクルブラケット<>をつかう書き方1だと、特定のファイルを1行読み込む「<ファイルハンドル>」という命令と混同しがちになるので、ここでは書き方2の使った方法を使う。

スカラーコンテキストでは、globはファイル名パターンにマッチするファイルのファイル名を1個ずつ返し、全ファイルを紹介したらundefを返す。
(スカラー:scaller値を一つ持つもの 対義語は配列array 105p)

次のプログラムは「*.html」というファイル名パターンにマッチするファイルのリストを表示する。

#listdir -- ファイル名のリスト表示

while ($file = glob("*.html")){
print "$file\n";
}

リストコンテキストでは、globはパターンにマッチするファイルの全ファイル名を一気に返す。
↓のプログラムは上のプログラムと同じ。

#listdir -- ファイル名のリスト表示

@file = glob("*.html");
foreach (@files){
print "$_\n";
}

@fileの配列がなくなるまで*.htmlのリストを表示する、と。

「ファイル名パターンを使って」ってのは、*.htmlとかのことだな。okok。

| | コメント (0) | トラックバック (0)

2008年9月 2日 (火)

「すぐわかるPerl」 8.1 ディレクトリ内のファイルを一気に処理する

前章ではフィルタを利用して一個のファイルを変換処理した。
複数のファイルを処理する場合には?

ここではディレクトリの中にあるファイルに連続適用する場合を考える。

repというperlで作成したコマンドを利用する。
このrepはフィルタの連続適用を行うコマンド。

rep フィルター名 変換後のファイルの拡張子 変換後のファイルの拡張子

たとえばあるディレクトリに

hiroko.html
eriko.html
takako.html
hitoe.html

があったとする。

rep ampsub html hhhh

というコマンド(repはperlで自作したコマンド)で

ampsub < hiroko.html > hiroko.hhhh
ampsub < eriko.html > eriko.hhhh
ampsub < takako.html > takako.hhhh
ampsub < hitoe.html > hitoe.hhhh

と同じことができる。

これを実現するには
・ディレクトリの中のファイル名を連続して取得する方法
・コマンドをpプログラムから実行する方法
が必要。

| | コメント (0) | トラックバック (0)

2008年8月27日 (水)

「すぐわかるPerl」 7.13 ダイヤモンド演算子<>

<>をダイヤモンド演算子という。
入力リダイレクションを渡された時は標準入力から、ファイル名を渡された時はそのファイルから入力を受け取る。

*nixのcatと同じように利用することもできる。

cat ファイル名
print <>;

は同じ。

print sort <>;

print reverse <>;

も動く。

| | コメント (0) | トラックバック (0)

2008年8月26日 (火)

「すぐわかるPerl」 7.12 ユーザーのオリジナルソート

7.11で作成した関数を使ってソートする

sort {$yymmdd($a) <=> &yymmdd($b)} 対象の配列 # 日付の比較、昇順
sort {$yymmdd($b) <=> &yymmdd($a)} 対象の配列 # 日付の比較、降順

<=>は「宇宙船演算子」で、数値の比較を行う。

プログラムの場合

# 日付ソート

print sort {$yymmdd($a) <=> &yymmdd($b)}(<STDIN>);

sub yymmdd{
省略
}

テストデータ

Apr 7th, 1984
April 1984 # いつの日かわからない
Apr 22nd # いつの年かわからない
lovelovelove #日付じゃない
the 17th of January 1984
11/7/1984
1983/12/25
1999/1 #いつの日かわからない

実行結果

1983/12/25
the 17th of January 1984
Apr 7th, 1984
April 1984 # いつの日かわからない
11/7/1984
1999/1 #いつの日かわからないApr 22nd # いつの年かわからない
lovelovelove #日付じゃない

| | コメント (0) | トラックバック (0)

2008年8月22日 (金)

「すぐわかるPerl」 7.11 ユーザーのオリジナル関数

前回の続き

> ■日付として昇順にソートする。
>
> 文字列の中に日付が現れる場合はどのようなパターンがあるか。
>
> Apr 7th ,1984
> the 7th of April 1984
> 4/7/1984
> 1984/4/7
>
> 考えていくときりがないので、いかにルールを決める。
> ・非数字に囲まれた4桁の数字は西暦
> ・Jan,Febという文字列が大文字、小文字関係なくあったら、それを月名と判断。
> ・ない場合には、いちばん最初の日数字に囲まれた二桁以下の数字を月名と判断する。
> ・Jan,Febが見つかった場合はいちばん最初の、見つからなかった場合には2番目の非数字に囲まれた二桁以下の数字を月名と判断する。
> ・上記の論理に当てはまらないものは一番後ろにソートする。

これを実現するための方法。

■オリジナル関数を定義する
Perlの関数(サブルーチン)の使い方は非常に簡単で、適当に名前をつけて呼び出すだけです。
呼び出されるほうは、プログラムの別の場所(プログラムの一番下にする)で次のように定義する。

sub 関数名 {
my (引数の入る変数のリスト) =@_;
いろいろあって;
returan (戻り値);
}

上のように書いた場合、上のsubから}までは

&関数名 (もしあれば引数のリスト);

という名前で評価されるときのみ実行される。

my ()の中の関数名をそのブロックの中でローカル化する。これで、ほかの場所で使った関数の結果で書き換わるということがなくなる。

@_ 引数のリストが入る配列。

return 戻り値を返す関数。

■日付を読み取って数値化する関数を作る
ある文字列$xを渡し、その中から
・非数字に囲まれた4桁の数字があったら、年とする
・january,February,あるいは、Jan,Febという文字列が大文字小文字関係なくあったらそれは月名と判断
・ない場合には、いちばん最初の非数字に囲まれた2桁以下の数字を月と判断
・Jan,Febが見つかった場合には、さいしょの日数字に囲まれた2桁以下の数字を月と判断し、2番目の非数字に囲まれた二桁以下の数字を日と判断。
・上記の論理で年月日が決まらない場合には、一番後ろにソートするために、年に9999を、月と日に99をセットする。

という論理で年と月と日を決定し、それが1984年4月12日なら
19840412という数値を返すへ関数を作成する。

sub yymmdd{
my ($x)=@_;

# yymmddという名前の関数を作る。
# 引数を$xに入れる。@_は引数のリストが入る配列(183p)。

my ($year,$mon,$day);

# メインの変数とぶつからないようにmyで宣言しておく。
# myで宣言した変数は、そのサブルーチンの中でローカル化される

if ($x =~ /(\D|\b)(\d\d\d\d)\D/i){
  $year = $2;
}else{
  $year = "9999";
}

# 非数字、または単語境界(空白や行頭)で囲まれた4桁の数字とマッチする場合にはそれをyearに入れる。
# 当てはまらない場合には$yearに9999を入れる。
# \D:数字以外
# \d:数字(digit)
# \b:単語境界(word boundary,153p)
# | :a|b と表記した場合、a かbにマッチする 154p
# /i:iスイッチ(大文字小文字無視、155p)
# =~:置換を指定した変数に代入(178p)

if ($x =~ /Jan/i){
  $mon="01";
} elsif ($x =~ /Feb/i){
  $mon="02";
}elsif ($x =~ /mar/i){
  $mon="03";
}elsif ($x =~ /Apr/i){
  $mon="04";
}elsif ($x =~ /May/i){
  $mon="05";
}elsif ($x =~ /Jun/i){
  $mon="06";
}elsif ($x =~ /Jul/i){
  $mon="07";
}elsif ($x =~ /Aug/i){
  $mon="08";
}elsif ($x =~ /Sep/i){
  $mon="09";
}elsif ($x =~ /Oct/i){
  $mon="10";
}elsif ($x =~ /Nov/i){
  $mon="11";
}elsif ($x =~ /Dec/i){
  $mon="12";
}else {
$mon =~undef;
}

# Janとマッチする場合、$monに01を入れる。
# 以下、月を数字に入れる。
# マッチしない場合には、$monにundefを設定

if ($mon){
  if(/(\D|\b)(\d\d?)(\D|\b)/){
   if(length($2) == 1){
    $day = "0".$2;
   } else {
    $day =$2;
   }
  } else {
  $day="99";
  }

# $monがundefではない場合
# 2行目のifに進む。
# 最初に出てきた非数字か単語境界に囲まれた1桁か2桁の数字を$dayに入れる。
# ?は正規表現では1個または0個を指す。

# 1桁の場合、頭に0をつける。
# .は文字列の連結

# マッチしない場合には99を入れる。

} elsif (/(\b|\D)(\d\d?)\D+(\d\d?)(\b|\D)/){
  if (length($2) ==1 ) {
   $mon = "0".$2;
   }else{
   $mon = $2
  }
  if (length($3)==1){
   $day = "0".$3
  } else {
   $day = $3;
  }
} else {
  $mon = $day = "99";
  }

# $monがundefの場合
# 最初に出てきた非数字(\D)か単語境界(\b...\b)で囲まれた1桁か2桁の数字(\d\d?、$2として記憶される)を
# $monに入れる。次に出てきた1桁か2桁の数字(\d\d?、$3に記憶される)を$dayに入れる。
# $dayも$monもひと桁の場合には0を先頭につける。
# このパターンにマッチしなかった場合、つまり2桁の数字か2組なかった場合には、$dayも$monも99を入れる。
#
#

  return ($year.$mon.$day);
}

# 最後に$yearと$monと$dayをつなげたものを返す。

長かったー

| | コメント (0) | トラックバック (0)

2008年7月 2日 (水)

「すぐわかるPerl」 7.10 リストコンテキストの

■<STDIN>を配列に代入する

@lines = <STDIN>;

こうすることで、標準入力の全行が配列に入る。

今まで使ってきたフィルター

while (<STDIN>){
print;
}

以下のように書き換えることもできる。

@lines = <STDIN>;
foreach(@lines){
print;
}

なお、printもリストコンテキストでは配列の要素を全部吐き出す。
基本のフィルターをこの観点から書き換えると

@lines = <STDIN>;
print @lines;

とも書けるし

print <STDIN>

と書いても同じ。
しかし、このままでは何の処理も挟めないためフィルターにならない。

■入力をソートして出力するフィルター

sortという関数は、配列を並べ替えたリストを返す。
特に指定しない限りは文字列として(辞書順に)昇順に並べ替える。
sortをはさんだフィルターは以下のようになる。

@lines = <STDIN>;
@sorted_lines = sort(@lines);
print @sorted_lines;

こうもかける。

@lines = <STDIN>;
print sort(@lines);

さらに短く

print sort(<STDIN>);

ちなみにreverseという関数は配列の順序をひっくり返した配列を出力する。
これを応用して、標準入力をひっくり返して出力するには

print reverse(<STDIN>);

この一行でいい。
・・・これはなにか美しさを感じるなぁ。うっとり。

sortについては指定することで並べ替えの論理を変えることが可能。

sort {$a cmp $b} 対象の配列 文字列比較、昇順(デフォルトと同じ)
sort {$b cmp $a} 対象の配列 文字列比較、降順
sort {$a <=> $b} 対象の配列 数値比較、昇順
sort {$a <=> $b} 対象の配列 数値比較、降順

{}の中には、ソートした結果が前に並ぶデータ$aと後ろに並ぶデータ$bが等しければ0
$aのほうが大きければ-1
$bのほうが大きければ1という三つの値を返す演算を入れる。

$a,$bは固定。
ただし、ブロック内のローカルな変数のため、ほかの場所でも$aや$bを利用することはできる。

<=>やcmpは比較の結果に応じて-1,0,1という三つの値を返す演算子。
<=>はその形から宇宙船演算子(spaceship operaor)といわれる・・・これは眉つばで聞いておこう。

■日付として昇順にソートする。

文字列の中に日付が現れる場合はどのようなパターンがあるか。

Apr 7th ,1984
the 7th of April 1984
4/7/1984
1984/4/7

考えていくときりがないので、いかにルールを決める。
・非数字に囲まれた4桁の数字は西暦
・Jan,Febという文字列が大文字、小文字関係なくあったら、それを月名と判断。
・ない場合には、いちばん最初の日数字に囲まれた二桁以下の数字を月名と判断する。
・Jan,Febが見つかった場合はいちばん最初の、見つからなかった場合には2番目の非数字に囲まれた二桁以下の数字を月名と判断する。
・上記の論理に当てはまらないものは一番後ろにソートする。

| | コメント (0) | トラックバック (0)

2008年7月 1日 (火)

「すぐわかるPerl」 7.9 splitとjoin

splitは文字を分割し、リストコンテキストでは全文分割結果を、スカラーコンテキストでは分割した個数を返す。

split(/区切り文字のパターン/,区切る対象,区切る上限個数)
split(/区切り文字のパターン/,区切る対象) # 区切れる限り区切ります
split(/区切り文字のパターン/) # 例のあれ $_ を区切ります
split # 空白文字で区切ります

joinは逆。

join(間にはさむ文字列,くっつける文字列のリスト)

例として、表計算ソフトのタブ区切りのデータをカンマ区切りに直す。

while(<STDIN>){
print join(",",split)."\n";
}

これは受け取った文字列を1行1行処理して
joinで , を間に挟み、くっつける文字列のリストがsplit、空白?ん??

あ、この場合のsplitは単に空白で区切るって意味か。
ん?でも、カンマで区切っているんだよなぁ。このsplitって何?
わからん・・・
空白をカンマに置換、ではないし・・・

あと、\nの前の「.」。これも何だ?
抜くとsyntaxエラーになるし・・・わからん。
正規表現?違うような。

わからないまま時間が過ぎるんで、先に進む。
そのうちわかる日が来るさ・・・たぶん。

でも、こういうところで疑問がわいたら、誰に聞けばいいんだろう・・・

さて。
CSVはデータが数字ではない場合に二重引用符で囲んでいる。
その場合も考えて、次のように変換

while(<STDIN>){     #一行ずつ受け取り
@elements = split;   #@elementsを空白文字で分割する
foreach(@elements){   #@elementsがなくなるまで下のループ文を実行
  if(/\D+/){   #ifによる条件分岐。\Dは数字以外[^0-9]。数字以外のものにマッチすれば真。
   $_ = "\"$_\"";  #if文が真の場合には$_の前後に"をつける。
  }
}
print join(",",@elements)."\n";  #joinでリスト@elementsを,でくっつけてprint
}

| | コメント (0) | トラックバック (0)

2008年6月25日 (水)

「すぐわかるPerl」 7.8 演算子「=~」

s///(置換)やtr///(交換)を$_以外のほかの変数に適用したい場合。
普通の変数の中身をパターンマッチで調査したいとき。

while(<STDIN>){
/(\S+) (\S+)/;
$m = $2;
$m =~ tr/a-z/A-Z/;
print "$m, $1\n";
}

実行結果。

PAGE, Jimmy
PAUL, John
BOHNAM, John
PLANT, Robert
RAY, Stevie

自分の理解用説明

/(\S+) (\S+)/;

\Sってのは、スペース以外の1文字以上。
これがスペースをはさんでつながっている。

$m = $2;

変数$mに後半の\Sを入れる。つまり、名字を入れる。

$m =~ tr/a-z/A-Z/;

$mの中身を大文字化

print "$m, $1\n";

$m(大文字変換済) と ,と$1を表示して表示し、終了。

うん。ok

| | コメント (0) | トラックバック (0)

2008年6月23日 (月)

「すぐわかるPerl」7.7 1文字単位の痴漢にtr///

特定の文字と特定の文字を交換する場合には、s///ではうまく動かない。
たとえば、XをYに変える場合。

s/X/Y/;
s/Y/X/;

一行目のsでXがYに変わってしまうため、うまく動かない。すべてXになる。
文字を交換する場合にはsではなく、trを利用する。

tr/XY/YX/

置換前と置換後を同じ文字数にすること。

tr/abcde/01234/;

これでaが0、bが1、cが2になる。

文字クラスと同様に連続したコードの範囲指定も可能。

tr/a-z/A-Z/;

これですべてが大文字になる。
作用対象は$_

$how_many_stars = tr/*/*/;
これで$_内の*の数を数える。

| | コメント (0) | トラックバック (0)

2008年6月17日 (火)

「すぐわかるPerl」 7.6 マッチした文字列と、その前後の文字列を扱う変数

$`:マッチする前までの文字列
$&:マッチした文字列
$':マッチした後の文字列

なお、$`の`はバッククォートと読む。
まず、ファイルを用意。

names.txt
Jimmy Page
John Paul Jones
John Bohnam
Robert Plant
Stevie Ray Vaughan

次のプログラムを実行。

# num -- 名前と名字を装飾付きで出力
$n=0;
while (<STDIN>){
chomp;
/ \S+ | /;
++$n;
print "*** $n ***\n";
print "Given Name:   $`\n";
if ($& ne " "){
print "Middle Name: ".substr($&,1,length($&)-2)."\n";
}
print "Family Name: $'\n";
print "\n";
}

実行結果

*** 1 ***
Given Name:   Jimmy
Family Name: Page

*** 2 ***
Given Name:   John
Middle Name: Paul
Family Name: Jones

*** 3 ***
Given Name:   John
Family Name: Bohnam

*** 4 ***
Given Name:   Robert
Family Name: Plant

*** 5 ***
Given Name:   Stevie
Middle Name: Ray
Family Name: Vaughan

ミドルネームがファイルにあるかどうかで表示を分けている。以下解説。

chomp;

これは$_の右側の改行コードを切り落とすのに使う。

/ \S+ | /;

左右に空白を持つ日空白1文字以上か、1文字の空白にマッチする。
つまり「ミドルネーム可、ファーストネームとラストネームの間の空白」にマッチする。

++$n;
print "*** $n ***\n";
print "Given Name:   $`\n";

番号付き見出し(*** 1 ***)と、名前の部分$`(マッチした文字列の前)
つまり、ミドルネームまたは名前と名字の間の空白をマッチ文字列として、その前の文字列を名前としている、と。

if ($& ne " "){
print "Middle Name: ".substr($&,1,length($&)-2)."\n";
}

$&はマッチ文字列。
$&が" "つまり空白でない場合にはprint文が処理される。

substrは部分文字列を返す関数。

substr(対象文字列,開始位置,長さ)

開始位置は通常0文字目。

lengthは文字列の長さを返す関数。

length(文字列)

結果的に

substr($&,1,length($&)-2))

は$&の1文字目から(文字列全体の長さから2を引いた)値まで。
具体的にはミドルネームの前後のブランクをカットする。

print "Family Name: $'\n";
print "\n";

これはわかる。
マッチした文字列の後の部分、つまり名字の表示。

■use Englishですっきり
Perlの特殊な変数($',$\,$`)をわかりやすいものに変えることができる。

先頭に
use English;

$_ $ARG れいのあれ
$. $INPUT_LINE_NUMBER現在入力中の行番号
$` $PREMATCH マッチ前
$& $MATCH マッチ文字列
$' $POSTMATCH マッチ後
$0 $PROGRAM_NAME 現在実行中のプログラム名

| | コメント (0) | トラックバック (0)

2008年6月11日 (水)

「すぐわかるPerl」7.5 カッコを使った記憶

■()の中で記憶された文字列は変数に入る

以下のような名前ファイルspeed.txtを作る

Hiroko Shimabukuro
Eriko Imai
Takako Uehara
Hitoe Arakaki

スピードかぁ、時代を感じるなぁ。
苗字と名前を逆転させ、間にカンマを入れるてみる。

while (<STDIN>){
s/(\S+) (\S+)/$2, $1/;
print
}

実行結果

Shimabukuro, Hiroko
Imai, Eriko
Uehara, Takako
Arakaki, Hitoe

おぉ。

s/(\S+) (\S+)/$2, $1/;

\S+はスペース以外の一文字以上。
それがスペース1つをはさんで、もう一つの同じものにつながっている。

()の中で記憶された文字列が$1,$2と順番に変数に入っていく。
それを逆転させている、と。

■$1、$2をマッチ演算子の後で使う。
$1,$2は置換文字列としてだけでなく、パターンマッチの後で好きなように使える。

$n = 0;
while (<STDIN>){
/(\S+) (\S+)/;
++$n;
print "*** $n ***\n";
print "Myouji: $2\n";
print "Namae:  $1\n";
print "\n";
}

実行結果

*** 1 ***
Myouji: Shimabukuro
Namae:  Hiroko

*** 2 ***
Myouji: Imai
Namae:  Eriko

*** 3 ***
Myouji: Uehara
Namae:  Takako

*** 4 ***
Myouji: Arakaki
Namae:  Hitoe

このようにかっこを使うと自由自在に文字列を加工できる。

| | コメント (0) | トラックバック (0)

2008年6月10日 (火)

「すぐわかるPerl」7.4 文字列の収集

■タグだけを出力するプログラム

逆に、タグだけを出力するプログラム。

while (<STDIN>){
@tags = /<.*?>/g;
foreach $tag(@tags){
print "$tag\n";
}
}

結果

<html>
<! -- love.html -->
<title>
</title>
<h1>
</h1>
<br>
<br>
</html>

マッチ演算子(//)はスカラーコンテキストで評価すると、マッチしたかどうか(真or偽)しか返さない。
マッチ演算子にgを指定すると「マッチするもの全部」という意味になる。そして、マッチしたものすべてを配列に入れる。
今回の例では@tagsという配列に代入させている。

■文字を収集する

タグから<>という文字を削除した部分を収集する場合。

マッチ演算子の中に()を書くと、パターン全体を返す代わりに、()で囲んだ部分だけが抽出されて配列に返される。

while (<STDIN>){
@tags = /<(.*?)>/g;
foreach $tag(@tags){
print "$tag\n";
}
}

おお。マッチしたものから、さらに()の中のものだけを配列に入れた、と。
ここで、忘れていたのでforeachの復習。

foreachは配列に連続アクセスするものです。
foreachで配列をひとつ一つ読み込み、ループ内の命令文を実行し、配列がまだ余っている時には、また配列を読み込みループする、と。
(107p)

■$_を使う

while (<STDIN>){  # この時点では$_は<STDIN>
@tags = /<(.*?)>/g;
foreach (@tags){ # この時点では$_は@tagsの各要素
print "$_\n";
}
}

うーん、わからん。foreachの理解が足りないのかなぁ。うーん
1行ずつ読み込み
@tagsという配列にマッチ演算子で合致したものを入れ
@tagsのある限り
printする

って感じ?
なんか、中学1年レベルの英訳している気分だ。

| | コメント (0) | トラックバック (0)

2008年6月 6日 (金)

7.3 最大マッチと最小マッチ

■HTMLからタグを削除する
htmlはちょっとは分かるので、いろいろ省略しつつ

タグとは(正規表現的に)
・"<" で始まり、 ">"で閉じられている
・"<>"のなかには何文字かあるので、「.」(任意の文字列)が*0回以上の繰り返し
となるので、正規表現的には

s/<.*>//g;

フィルタにしてみる

# tagdel -- タグを削除
while(<STDIN>){
s/<.*>//g;
print;
}

love.htmlを用意して表示。
cat love.html

<html>
<! -- love.html -->
<title>Love Home Page</title>
<h1>Love Home Page</h1>
Welcome to our page!<br>
Love is great<br>
&#169;1999-2000 Love organization &#169;1999-2000 heart corp
</html>

love.htmlをさっき作ったフィルタにかける

# perl perltest.pl < love.html

Welcome to our page!
Love is great
&#169;1999-2000 Love organization &#169;1999-2000 heart corp

なんか少ない・・・
<h1>と<title>タグの部分が丸々無いのか。

■最大マッチにするには
たとえば、
<title>Love Home Page</title>

s/<.*>//g;

で置換を行ったとき、次の二通りの解釈が成り立つ。
「<」ではじまり間に任意の文字を含み「>」で終わるという条件。

<title>Love Home Page</title>(前後のタグだけ)
<title>Love Home Page</title>(タグで囲まれた1行丸まる)

perlには二通り以上の解釈が成り立つ場合には長いほうをとるという原則があるため、行ごと削除される。
これが<h1><title>部が消えた原因。
対策としては
「「<」で始まり「>」で終わる、「>」以外の文字列」
わからん・・・答えの置換式から見るか。

s/<[^>]*>//g

「<」で始まり「>」で終わり、かつ途中に「>」を含まない。
これだ!

■最小マッチにするには

マッチ演算子の繰り返しに「?」をつけると最小マッチになる。

# tagdel -- タグを削除
while(<STDIN>){
s/<.*?>//g;
print;
}

?は*以外にも+や{n,m}にもつけられる。
{n,m}と書くとn回以上m回以下の繰り返しと評価されるが,{n,m}?と書くと短いほうにマッチする。

たとえば、sumomomomomomomomomoというデータがあった場合。

s/su(mo){2,5}//;

という置換文の場合、検索側は最長一致の原則でmoが5回合致しているとみなし

sumomomomomomomomomo

が削除され、

momomomo

になる。

s/su(mo){2,5}?//;

になった場合(最小マッチ)の原則により

sumomomomomomomomomo

までが削除され、

momomomomomomo

が残る。

| | コメント (0) | トラックバック (0)

2008年5月28日 (水)

7.2 文字列の削除

置換文字列を殻にすると、マッチした文字列は削除される。

s/置換文字列//g

7.1で作成したampsubを実態参照を消してしまう設定にする場合

検索する場合には正規表現が利用可能なので、
・&#で始まり
・最大三3桁の数字で表現され(つまり\d(数字であり、文字クラス[0-9])で
 {1,3};(1つから3つまでの繰り返し、つまり1桁から3桁))
・;で終わる
文字列を消すともいえる。

# ampdel -- 実態表現を削除

while <STDIN>{
s/&#\d{1,3};//g;
print;
}

| | コメント (0) | トラックバック (0)

2008年5月27日 (火)

「すぐ分かるPerl」7.1 置換処理

■置換演算子「s///」

これは知ってるー。よく404 blog not found の弾さんが使っているので。

今回データとして扱うのはhtmlファイル。
なんかやっとそれらしくなってきた感じだ~!
でも、動的ページ作成とかにはまだまだっぽ行けど、ゆっくりしっかりやっていこう。
最初の一冊だし。

<html>
<! -- love.html -->
<title></title>
<h1>Love Home Page</h1>
Welcome to our page!<br>
Love is great<br>
&#169;1999-2000 Love organization &#169;1999-2000 heart corp
</html>

この中の、「&#169;」を「&copy;」に置換する。

置換演算子の記述の仕方。
sはsubstituteの略。対象は「例のあれ」$_

s/置換前のパターン/置換後のパターン/

置換演算子として記述すると、こうなる

s/&#169;/&copy;/

基本のフィルター。
(思い出してかけたよ!)

while (<STDIN>){
print;
}

置換処理を挟んだフィルター(smpsub.pl)

#! /usr/local/bin/perl
# ampsub -- 実体参照を置換(実はバグっている)

while (<STDIN>){
s/&#169;/&copy;/;
print;
}

このフィルタをつかってみる。
久々にwindowsで実行

C:\Documents and Settings\sironekotoro\デスクトップ>perl "C:\Documents and Settings\sironekotoro
\デスクトップ\ampsub.pl" < love.html > love2.html

実行結果

&copy;1999-2000 Love organization &#169;1999-2000 heart corp

最初の箇所しか置換されていない。
これは置換演算子の特性によるもの。
最後にg(これはglobalの略)を加える事で、すべての文字列の置換を行う。

s/置換前のパターン/置換後のパターン/g

フィルタの場合には

#! /usr/local/bin/perl
# ampsub -- 実体参照を置換(実はバグっている)

while (<STDIN>){
s/&#169;/&copy;/g;
print;
}

となる。これで実行すると、すべての置換が行われる。

■複数の置換演算子を書く

置換演算子は連続して記述が可能。他のアスキーアコードも分かりやすく変換。

# ampsub

while(<STDIN>){
s/&#34;/&quot;/g; # 引用符(quote)  '
s/&#38;/&amp;/g; # アンパサンド(ampersand) &
s/&#60;/&le;/g;  # 小なり(less than)  <
s/&#62;/&gt;/g;  # 大なり(grater than)  >
s/&#153;/&trade;/g; # 商標(trade mark)  (TM)
s/&#163;/&pound;/g; # ポンド記号(pound)  £
s/&#165;/&yen;/g; # 円記号(yen)   \
s/&#169;/&copy;/g; # 著作権(copyright)  (C)
s/&#174;/&reg;/g; # 登録記号(registered) (R)
print;
}

■メモ
グローバル置換のgスイッチと大文字小文字を無視するiスイッチを併用することができる。

s/hi/hello/gi

とすると、全文のなかのhi,HI,Hi,hIが「hello」に変わる。

■メモ
フィルタを利用してデータを置換するときは、下記の順番を取る。
1.フィルター < 変換前 > 変換後
2.変換前と変換後を比較
3.「mv 変換前 変換後」で変換後で変換前を上書き

| | コメント (0) | トラックバック (0)

2008年5月12日 (月)

「すぐ分かるPerl」6.7 その他の正規表現

■文字クラス
[abc] aかbかcのどれか
[a-z] アルファベット任意の小文字
[^abc] aでもbでもcでもない文字
\d 数字(digit)
\D 数字以外
\w 英数字(word)
\W 英数字以外
\s 空白文字(space)
\S 空白文字以外
\b 単語境界(word boundary)
. 任意の一文字

単語境界とは、英数字と空白または文字列の端との間を意味する
/Jackson/ だと Jacksons にもマッチするが
/\bJackson\b/ だと「 Jackson 」という単語つまり前後に空白か文字列の端がある場合にしかマッチしない。

■繰り返し
文字、または文字クラスをxとしたばあい
x* 0回以上の繰り返し
x+ 1回以上の繰り返し。xx*と同じ
x? 0回か1回
x{5} 5回繰り返し。xxxxxと同じ。
x{3,} 3回以上繰り返し。xxx+と同じ
x{3,5} 3回以上5回以下繰り返し。xxxx?x?

このあたりはちょっと分からないというか、0回以上と1回以上とか、なんかわからん。

■グループと選択
文字列を繰り返すときは()をつかってグループ化する。

su(mo)+ sumo,sumomo,sumomomomoなどにマッチする。

いくつかのパターンのうち、どれかにマッチさせる場合には|を使う。

Love|kiss loveかkissにマッチする
stud(y|ies) studyかstudiesにマッチする
su(mi|mo){2,3} sumimi,sumimo,sumomi,sumomo,
        sumimomi,sumomimi,sumomomi,sumomomi,sumomomimo,sumimomo,sumomomoのいずれかにマッチ

■位置指定
パターンの位置を指定する
^ 先頭
$ 末尾

■エスケープ
/,^,\などの正規表現的に意味のある特殊記号自体を検索したい局面では、\でエスケープする。

^\^ ^で始まる行にマッチ
\\ \自体にマッチ

\は特殊記号の前ではエスケープという意味になるが、特殊記号でなければエスケープはされず書かないのと同じという意味合いになる。

/\o\)\+\>/

o)+>

という文字列にマッチする。
いちいち\を挟むのが面倒な場合には\Qと\Eの間に挿入される文字列を全部の前に\が挿入されるのと同じとして扱う事が出来る。

/\Qo)+>\E/

■iスイッチ
マッチ演算子の末尾にiをつけると、大文字小文字を無視する。ignore caseの略。

/hi/i

とした場合、これは

hi,Hi,hI,HIにマッチする。

■区切り文字を変えるm
区切り文字はスラッシュ出なくても良い。

m|パターン|

m#パターン#

と書いてもマッチ演算子化する事が可能。
mの直後の文字が区切り文字となる。

スラッシュ5個に一致、という条件を設定した場合には、\記号を使うとエスケープが必要となり
/\/\/\/\/\//
と記述しなくてはいけないが、区切り記号を「|」に変えることで、/をエスケープする必要がなくなり、

m|/////|

と記述できる(という認識でいいのだろうか・・・?)

| | コメント (0) | トラックバック (0)

2008年5月 8日 (木)

「すぐ分かるPerl」6.6 正規表現による検索

正規表現について。
これは時々業務でつかいます。ログの中から該当する文字列見つけるのに使ったり。

# num -- goodの文字列を含む行を出力
while (<STDIN>) {
if(/Good/){
print;
}
}

出力結果

perl perltest.pl < greetings.txt
Good Morning
Good bye

ここでの「/文字列/」をマッチ演算子という。
デフォルトの作用対象が$_

ファイル(people.txt)を作成する。

Michal Jackson
Janet Jackson
Joe Jackson
Joni Mitchel
Jackson 5
Michal Johnson
Jon Anderson
Sade
Hiroko Shimabukuro
Eriko Imai
Takako Uehara
Hitoe Arakaki
John Paul Jones
14 carats soul
Prince
UK
US3

時代を感じるラインナップだなぁ・・・
苗字がJacksonの人を検索する場合。

/Jackson/

# num -- Jacksonの文字列を含む行を出力
while (<STDIN>) {
if(/Jackson/){
print;
}
}

出力結果

perl perltest.pl < people.txt
Michal Jackson
Janet Jackson
Joe Jackson
Jackson 5

グループ名のJackson5まで一致したと判断されるため、末尾に一致する場合の未表示とする。

# num -- Jacksonの文字列を含む行を出力
while (<STDIN>) {
if(/Jackson$/){
print;
}
}

うーん、これがうちの環境ではなぜかうまく出ない・・・

本来であれば

Michal Jackson
Janet Jackson
Joe Jackson

という結果が出るのだけど、何も結果が表示されない。
$を追加するだけだから、間違いないはずなのになぁ。

とりあえず、先に進む。

先頭にマッチングさせる場合には^を付与する。
Jから始まるものを書き出す場合

# num -- Jacksonの文字列を含む行を出力
while (<STDIN>) {
if(/^J/){
print;
}
}

これは出た。

perl perltest.pl < people.txt
Janet Jackson
Joe Jackson
Joni Mitchel
Jackson 5
Jon Anderson
John Paul Jones

数字を含むものの場合、文字クラスをつかう。

/[0123456789]/

複数の文字のどれかにマッチするパターン

連続した文字コードの場合には範囲指定も可能。

/[0-9]/

これで0から9までの文字コード1文字にマッチする。

perl perltest.pl < people.txt
Jackson 5
14 carats soul
US3

数字を含まない、場合にはクラスの先頭に^を付与する
/[^0-9]/
ただし、これは「数字以外の文字をふくむ」場合にマッチすることになり、数字以外の普通の文字が含まれればマッチしてしまう。

文字列の最初から最後まで数字以外、という場合にはこのようになる。

/^[^0-9]+$/

最初の^は先頭をあらわし、次の^は[]つまり文字クラスの中なので否定をあらわし、+は1回以上の繰り返し、$は末尾。

# num -- Jacksonの文字列を含む行を出力
while (<STDIN>) {
if(/^[^0-9]+$/){
print;
}
}

出力結果

perl perltest.pl < people.txt
Michal Jackson
Janet Jackson
Joe Jackson
Joni Mitchel
Michal Johnson
Jon Anderson
Sade
Hiroko Shimabukuro
Eriko Imai
Takako Uehara
Hitoe Arakaki
John Paul Jones
Prince
UK

これはうまくいった!
で、さらにJから始まるという条件を付与する。

# num -- Jacksonの文字列を含む行を出力
while (<STDIN>) {
if(/^J[^0-9]+$/){
print;
}
}

出力結果

perl perltest.pl < people.txt
Janet Jackson
Joe Jackson
Joni Mitchel
Jon Anderson
John Paul Jones

おー。すばらしい。

perlの場合には数字以外の一文字というのはあらかじめ組み込まれている。

\Dと書くと、[^0-9]と同じ意味になる。つまり

/^J\D+$/

と書いても同じ意味になる。

なお、数字一文字は\dであり、これは

/[0-9]/

と同じ意味合いを持つ。

●一語の名前を検索

US3やPrinceなど一語で終わるものをマッチさせるには、スペース以外で終始すればいい。スペース以外を示すには\Sという文字クラスがある。

/~\S+$

\Sと\sは分かるのだけど、このスペース以外で終止するという意味が分からなかった。

●3語の名前を検索

これは「スペース以外」+「スペース」+「スペース以外」+「スペース」+「スペース以外」の組み合わせで実現させる。

/^\S+\s+\S+\s+\S+$/

とあるのだが、なぜかうまくいかないので

/^\S+\s+\S+\s+\S/

でok。
ウチの環境は正規表現の末尾の扱いが違うのかなぁ。まぁいいや。

| | コメント (0) | トラックバック (0)

2008年5月 1日 (木)

「すぐ分かるPerl」6.5 行番号をうってみよう

1: # copycat -- 標準入力を標準出力にコピー
2:
3: while (<STDIN>){
4:  print;
5: }

うむー。
考えたけど、分からなかったので解答をみながら。
たとえばこんな感じ。

# num -- 番号を振りながらコピー
$i=0;
while (<STDIN>) {
print ++$i;
print ": ";
print;
}

あるいは

# num -- 番号を振りながらコピー
$i=0;
while (<STDIN>) {
print ++$i.": ".$_;
}

行番号自体は「$.」という特殊変数に格納されているので、実は下も同じような結果になる。

# num -- 番号を振りながらコピー
while (<STDIN>) {
print $..": ".$_;
}

教科書例はこれ。
なるほど、1行にまとめて""のなかで変数を展開していると。

# num -- 番号を振りながらコピー
while (<STDIN>) {
print "$.:$_";
}

なるほど。
自力でこれくらいは寝てても書けるようになりたいなぁ。
数こなすしかないかな。がんばろう。

| | コメント (0) | トラックバック (0)

2008年4月30日 (水)

「すぐ分かるPerl」6.4 謎の物体「$_」

6.3の復習
・<STDIN>は標準入力
・渡されたファイルなどを一行ずつ読み込む

# copycat -- 標準入力を標準出力にコピー
while (<STDIN>){
print;
}

これは以下のように書いても同じ

# copycat -- 標準入力を標準出力にコピー
while ($_ = <STDIN>){
print $_ ;
}

・whileの条件文の()のなかに単独で<STDIN>と書くと、<STDIN>を評価するたびに$_に<STDIN>がセットされる。
・Printで出力するものを省略すると、$_を出力する

これは、スカラーコンテキストとして<STDIN>が呼ばれている場合。
リストコンテキストとして呼ばれている場合の動作は後述。

→ 4.4にスカラーコンテキストとリストコンテキストの違いについて記述あり

| | コメント (0) | トラックバック (0)

2008年4月24日 (木)

「すぐ分かるPerl」6.3 標準入力を読み込む

■<STDIN>は入力した行という値になる

<STDIN>とはstanard inputつまり標準入力の略。
一回呼び出すごとに標準入力から1行のデータを読み出してその値になる。
※スカラーコンテキストとして呼ばれた場合

#1st3 -- <STDIN>

$a = <STDIN>;
$b = <STDIN>;
$c = <STDIN>;

print $a;
print $b;
print $c;

実行結果
perl perltest.pl < greetings.txt
Good Morning
Hello
Good bye

■<STDIN>を呼び出し続けるとどうなるか

#1st10 -- <STDIN>

$a = <STDIN>;
$b = <STDIN>;
$c = <STDIN>;
$d = <STDIN>;
$e = <STDIN>;
$f = <STDIN>;
$g = <STDIN>;
$h = <STDIN>;
$i = <STDIN>;
$j = <STDIN>;

print $a;
print $b;
print $c;
print $d;
print $e;
print $f;
print $g;
print $h;
print $i;
print $j;

結果は

perl perltest.pl < greetings.txt
Good Morning
Hello
Good bye
Thank you
Good Night

つまり、本のファイル「greetings.txt」のすべての行を出し切って何もしない。

6.1で出たものを再確認。

while(<STDIN>){
print;
}

このperlにテキストファイルを食わせると、<STDIN>が1行ずつ取り込み、printで処理していく。
処理する行がなくなると、<STDIN>がundefの値となり、whileループを抜ける。

次回も続く。

| | コメント (0) | トラックバック (0)

2008年4月23日 (水)

「すぐ分かるPerl」6.2 フィルターを使う

■フィルターを使ってみる
割愛。
ただ、uniq(重複するものをひとつにする)が隣り合った行しかまとめないというのは実ははじめて知った。
なるほど、それでsortしてからuniqなのか。

■フィルターを作ってみる
・・・!おぉ、なんかすげー

入力をそのままコピーするフィルター

# copycat -- 標準出力を標準出力にコピー

while(<STDIN>){
print;
}

実行してみる、が、Windowsだとなんかうまくいかないので久々にLinux上で実行。

perl perltest < greetings.txt
Good Morning
Hello
Good bye
Thank you
Good Night

おーでたでた。
ちなみに、STDINは初出。
全然記憶になかったんで忘れたかと思ったわ。

| | コメント (0) | トラックバック (0)

2008年4月22日 (火)

「すぐ分かるPerl」6.1 ファイルへの出力

標準出力(画面への出力)については既に学習している

#calc -- hello 挨拶プログラム
print ("Hello\n");

テキストファイルへの出力を行う場合には、ファイル名を指定してリダイレクトを行う。

hello > aisatsu.txt

例)

# iloveyou50000 -- I love you と50000回言う
for ($i = 1; $i<=50000;++$i){
print ("I LOVE YOU!\n")
}

I LOVE YOU が50000行続くファイルが作られる

--------
普段仕事でlinuxつかっているのでリダイレクトはok
ただ、最初の例文で何で()が必要なのか分からん・・・
print "hello\n"
でもいいような。

次の例文ではforループの復習。
意図しているところは分かるのだけど、思い出せなかった。
forについては87p

for(最初に実行する文 ; ループ継続を判定する文 ; ブロックの最後にやる文;){
命令1;
命令2;
}

| | コメント (0) | トラックバック (0)

2008年4月17日 (木)

「すぐ分かるPerl」5.7 文字列の置き換え

■*は渡せない

#calc -- 電卓プログラム 引数版
$x = eval($ARGV[0]);
print "$x\n";

の場合、*が数式の中に含まれるとエラーになる。
(Windows上で実行させた場合は大丈夫みたい)

これは、Unix等でファイル名をマッチさせる際のワイルドカードとして「*」が用いられるため。

■*をxで置き換える
*はOSとかシェル上の処理で必要なため、別の文字で置き換える。
形が似ているのでxで置き換える。

置き換えの場合には

$置換対象の文字列の変数 =~ s/置換前/置換後/g;

「=~」イコールチルダでワンセット。
s は substituteで「置き換え」
g はグローバルで「全体的に」

#calc -- 電卓プログラム 引数版
$ARGV[0] =~ s/x/*/g;
$x = eval($ARGV[0]);
print "$x\n";

これで

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl" 2*3
6

となる。
ちなみに、実際に出たミスだけど

#calc -- 電卓プログラム 引数版
$ARGV[0] = ~ s/x/*/g;
$x = eval($ARGV[0]);
print "$x\n";

とすると・・・(つまり、= と ~ の間をあける)

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl" 2*3
4294967295

となる。
なぜだ!?

それはともかく、dankogaiのblogとか見てると良く「s/なんたら/かんたら/g」ってのが出てくるけど、これは置換をしていたんだなぁ、と再認識。

| | コメント (0) | トラックバック (0)

2008年4月16日 (水)

「すぐわかるPerl」5.6 めちゃめちゃ便利なeval

引数のみで計算の出来るようなプログラムを作る場合。
たとえばこんな感じ。

calc (32000+12000+4000)/7
6857.14285714286

プログラムの外側

calc -- 電卓プログラム 引数版
$x = $ARGV[0];
print "$x\n";

これで、引数がそのまま表示されるようになる。

しかし、この後式を計算するロジックを作ろうとすると大変になる。
・四則演算
・文字 + , - , ( , ) = の扱い。

perlの場合には、evalという関数を利用して楽にする事が出来る。

calc -- 電卓プログラム 引数版
$x = eval($ARGV[0]);
print "$x\n";

これで計算が可能になる。
evalで囲んだだけ。

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl" (32000+12000+4000)/7
6857.14285714286

これは、引数$ARGV[0]の文字列をevalに渡し、その結果を$xに代入する。
すると、文字列はその場で実行される。これを「Perlプログラムとして評価される」という。

evalはevaluate(評価する)の意味。

評価した結果、つまり、計算した結果が$xに入る。

| | コメント (0) | トラックバック (0)

2008年4月15日 (火)

お仕事でつかったperl

初めて自分で考えて作ってみたperlスクリプト。

#192.168.1.0~192.168.1.255まで並べる
$ip = 0;
while($ip < 255){
$ip += 1;
print "192.168.1.$ip\n"
}

excelでやった方が早いとか言わないで><

| | コメント (0) | トラックバック (0)

「すぐわかるperl」5.5 無数の引数の利用

5.5 無数の引数の利用

たとえば、いくつ物数を渡してその合計を返すプログラムを考える。

add 1 2 3 4 5 6 7 8 9 10
55

この場合、足す数がいくつあるか分からないところがポイント。
→ foreachを利用する。

#add -- 引数を合計する

$sum = 0; #変数の初期化

foreach $each_val(@ARGV){ #まずforeachで$ARGV[0]
$sum += $each_val; #が$each_valに代入され、{}内の処理($sumに加算)
    #が行われる。
}    #その後にforeachで$ARGV[1]が処理される。
    #これが引数がなくなるまで行われる。
print "$sum\n";

#ARGV:ARGument Value:引数の値

| | コメント (0) | トラックバック (0)

2008年4月11日 (金)

「すぐわかるperl」5.4 エラーチェックをしてみよう

前項では特にエラーチェックを行っていないため、存在しない三角形の面積を求めようとすると柿のようなエラーが出る
例:3辺が1 1 50

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl" 1 1 50
Can't take sqrt of -390000 at C:\Documents and Settings\sironekotoro\デスクトップ\perlte
st.pl line 7.

これは、-390000の平方根が計算できないとのエラーです。
(マイナスの平方根は虚数)

エラーチェックは
・引数が3個かどうか
・sqrt(平方根)の中身がプラスになるか
の二点で行う。

#helon -- ヘロンの公式で三角形の面積を求める

if (@ARGV -3){
die "hikisuu wa 3 ko de aru hitsuyouga ari masu!\n"
}

($a,$b,$c) = @ARGV;
$s = ($a + $b + $c)/2;

if (($size2=($s * ($s - $a)*($s - $b)*($s - $c)) < 0{
die "sonnna sankakkeiha arimasen!";
}

$size = sqrt($size2);
print "$size\n";

これで、ウィルスチェックが働く。

| | コメント (0) | トラックバック (0)

2008年4月10日 (木)

「すぐわかるperl」5.3 決まった数の引数の利用

三角形の面積を求める式は「底辺×高さ÷2」
しかし、高さを出すのが難しい場合には「ヘロンの公式」を利用する。

ヘロンの公式 - Wikipedia
http://ja.wikipedia.org/wiki/%E3%83%98%E3%83%AD%E3%83%B3%E3%81%AE%E5%85%AC%E5%BC%8F

この公式を利用して三角形の面積を出す場合には、3辺の情報があればよい。
この3辺の情報を引数として設定するプログラムを作る。

#helon -- ヘロンの公式で三角形の面積を求める

$a = $ARGV[0];
$b = $ARGV[1];
$c = $ARGV[2];
$s = ($a + $b + $c)/2;
$size = sqrt($s * ($s - $a)*($s - $b)*($s - $c));
print "$size\n";

テストとして、3辺が3,4,5の三角形(5を斜辺とする直角三角形)でテスト。
この場合には3*4/2で6が面積となる。

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl" 3 4 5
6

うまく動いていると、今のところは判断。
次回は今回の式で対応できない数字を入れられた場合のエラーチェックなど。

| | コメント (0) | トラックバック (0)

2008年4月 8日 (火)

「すぐわかるPerl」5.2引数は配列

■引数の特徴
・文字列である
・何個か分からない

Perlの場合には、引数は自動的にもともと備え付けられている配列変数@ARGVに自動的に代入されていく。
ARGVとはargument(引数)value(値)の略です。

#argtest -- 引数のテスト
print "$ARGV[0]\n";
print "$ARGV[1]\n";
print "$ARGV[2]\n";
print "$ARGV[3]\n";

このプログラムを実行すると、改行のみが表示される。

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\argtest"

C:\Documents and Settings\sironekotoro>

loveという引数を与えてみる

argtest love

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\argtest" love
love

C:\Documents and Settings\sironekotoro>

引数を増やしてみる

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl" love kiss
love
kiss

C:\Documents and Settings\sironekotoro>

引数を3つにしてみる
C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl" love kiss hug
love
kiss
hug

C:\Documents and Settings\sironekotoro>

■引数の個数を調べる

#argtest -- 引数のテスト
$x = @ARGV;
print "$x\n";
print "$ARGV[0]\n";
print "$ARGV[1]\n";
print "$ARGV[2]\n";
print "$ARGV[3]\n";

結果。

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl" love kiss hug
3
love
kiss
hug

C:\Documents and Settings\sironekotoro>

| | コメント (0) | トラックバック (0)

「すぐわかるPerl」5.1プログラムに引数を渡すとは

ls -la

上の式で言うところの「-la」の部分ですね。

| | コメント (0) | トラックバック (0)

2008年4月 3日 (木)

「すぐわかるPerl」4.9 エラーメッセージを出して死ぬ「Die」

4.8のforeachで、人数がゼロだった場合

#! c:\perl\bin\perl.exe
# average - 平均身長を求める(人数がゼロ)

@tall=();
foreach $each_tall (@tall){
$sum += $each_tall;
}
$ave = $sum / @tall;
print "average;$ave\n";

実行結果

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl"
Illegal division by zero at C:\Documents and Settings\sironekotoro\デスクトップ\perltest
.pl line 8.

エラーメッセージの内容は、ゼロで割り算が行われた、という内容。
このメッセージが出ないように、人数がゼロだったらその旨のメッセージを出す部分を追加。
unlessはifの逆で、条件に満たないときに実行される。
この場合には、配列@tallの要素数はゼロになるため、偽となる。

#! c:\perl\bin\perl.exe
# average - 平均身長を求める(人数がゼロ・修正版)

@tall=();

unless (@tall){
die "list ga 0 nin desu. heikin ga dasemasen!\n"
}

foreach $each_tall (@tall){
$sum += $each_tall;
}
$ave = $sum / @tall;
print "average;$ave\n";

実行結果

C:\Documents and Settings\wada>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl"
list ga 0 nin desu. heikin ga dasemasen!

と、実のあるメッセージになる。

| | コメント (0) | トラックバック (0)

2008年3月21日 (金)

「すぐわかるPerl」4.8 配列を連続アクセスする「foreach」ループ

foreachはwhileやforと同じで、繰り返しを行う制御文

ちょっと復習
while(76p)

while(繰り返し条件){
命令1;
命令2;
}

for(87p)

for(最初に実行する文;ループを継続するか判定する文;ブロックの最後にやる文){
命令1
命令2;
}

平均身長プログラムでforeachを使ってみる

#! c:\perl\bin\perl.exe
# average - 平均身長を求める

@tall=(155.5,160,162.4,173,173.8,180.5,178.2,145.9,155.5,162.8);
foreach $each_tall (@tall){
$sum += $each_tall;
}
$ave = $sum / @tall;
print "average;$ave\n";

この中のforeachに注目

foreach $each_tall (@tall){{
$sum += $each_tall;
}

これは$sumに配列の数(155.5とか160とか)を一個ずつ入れていくための部分。

foreach $each_tall (@tall){
まず、0番目の要素を処理する
$tall[0]=$each_tall

その$each_tallを$sumに加算する。
$sum += $each_tall;

foreachはループなので、今度は1番目の要素を処理
$tall[1]=$each_tall

foreachはこれを要素の数だけ行う。

・・・ってことでいいのだろうか、オレ解釈だが。

で、foreachループを抜けた後に$sum(配列の数の合計が入っている)を@tall(配列の数、つまり10個)で割る。
(@tallは数式の中で扱われる場合にはリストではなくスカラーコンテキストとして扱われる 101p)

| | コメント (0) | トラックバック (0)

2008年3月19日 (水)

4.7 スライスと範囲演算子「..」

配列の(複数の)一部分だけを使ってリストを作ることが出来ます。たとえば、@tallの最初から3番目までは下のようにかける

($tall[0],$tall[1],$tall[2])

これを次のような略記法で書く事が出来る

@tall[0,1,2]

このように配列の一部を使ったリストをスライスといいます。
先頭の記号が@なのに注意する。
スライスはリスト同様、代入演算子 = の右辺(読み取られる側)にも左辺(書き換わる側)にもなれる。@tallの1個目と2個目の交換をスライスを使って書くとこうなる

@tall[0,1] = @tall[1,0];

10個の要素からなる配列@tallの奇数版芽だけを取り出して新配列を作ることも出来ます。

@tall[1,3,5,7,9];

奇数番目と偶数番目を交換することも出来る。

@tall = @tall[1,0,3,2,5,4,7,6,9,8];

前半だけを取り出す

@Lowtall = @tall[0,1,2,3,4];

この場合には略記法により下のように書く事が出来る。

@Lowtall = @tall[0..4];

リストのスライスも同様に作ることが出来る

@top3 = (185.3,180.5,173.5,170.2,169.9)[0,1,2];

略記法を使った場合

@top3 = (185.3,180.5,173.5,170.2,169.9)[0..2];
※既に降順で並べてある

いずれの方法を使っても、@top3には185.3,180.5,173.5が入る

■範囲演算子
点2個の演算子「..」には注意。
これは、リストコンテキストでは左の数から右の数まで1ずつ増やした数列(つまりリスト)を返す。

@from100to110 = 100..110

これで@from100to110には(100,101,102,103,104,105,106,107,108,109,110)という11個の数字が入る。

身長上位3名のスライスを得る場合には

@top3index = 0..2
@top3 = (185.3,180.5,173.5,170.2,169.9)[@top3index]

でも良い。
これは

@top3 = (185.3,180.5,173.5,170.2,169.9)[0..2]

または

@top3 = (185.3,180.5,173.5,170.2,169.9)[0,1,2]

とおなじ。

| | コメント (0) | トラックバック (0)

2008年3月18日 (火)

「すぐわかるPerl」4.6 配列操作のいろいろ

■変数の交換
変数$aと$bの内容を交換する場合、↓のようにしなくても良い。

$a = $tmp;
$a = $b;
$tmp =$b;

というような中間変数を用いることなく可能。
具体的には

($a,$b)=($b,$a);

これで変数の交換が終了。
 これは強力に便利です。
・・・そうなのか?なんか利用法思いつかないや。

配列の要素の交換も同様に可能。@tallの1個目と2個目を変える場合には↓のように書く。

($tall[0],$tall[1]) = ($tall[1],$tall[0])

■最後の要素のアクセス
配列の最初の要素は「$配列名[0]」でアクセスする。
では、最後の要素の場合にはどうなるか?

「@配列名」という配列を作ると、「$#配列名」という最後の要素のインデックスが作成される。
最後の配列は

$配列名=[$#配列名]

となる。

スカラーコンテキスト(4.4章)の場合には、「@配列名」は配列の個数という数値になるので、「$#配列名」は「@配列名-1」に等しくなります。

「$#配列名」は「@配列名-1」

なお、配列のインデックスに府の数を指定すると、配列を後ろからアクセスします。

$配列名[-1]

と書いても、配列の最後の要素にアクセスできます。

$配列名[-2]

とすると、最後から2番目にアクセスできる。

#! c:\perl\bin\perl.exe
# arraytest -- 配列の実験

@move = ("hop","step","jump","slip","down");

print "$move\n";
print "$move[$#move]\n";
print "$move[@move - 1]\n";
print "$move[-1]\n";
print "$move[-2]\n";

というプログラムを実行すると、

C:\Documents and Settings\wada>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl"

down
down
down
slip

となる。以下解説(オリジナル)。

print "$move\n"; #moveという変数の初期化?
print "$move[$#move]\n"; #配列名@moveの最後の配列
print "$move[@move - 1]\n"; #配列名@moveの最後の配列
print "$move[-1]\n"; #配列名@moveの最後の配列
print "$move[-2]\n"; #配列名@moveの最後から2番目の配列

■メモ
変数は$、scallar
配列は@、array
と覚えてみる。

| | コメント (0) | トラックバック (0)

2008年3月13日 (木)

「すぐわかるPerl」4.5 配列は勝手に伸び縮みする

@tall = (145.8,155.2,180.2);

これで配列は3個になる。

@tall = (145.8,155.2,180.2);
@tall = (145.8,155.2);

このように二つの命令をれな属して行うと、一つ目の代入文で3個出来た配列の長さは2個に縮み、一つめの代入文で入った180.2、つまり$tall[2]は削除される。

$tall[5]=200;

プログラムの先頭でぽつんとこの命令を実行すると、$tall[0],$tall[1],$tall[2],$tall[3],$tall[4],$tall[5]の6つの要素が作成される。
$tall[5]には200が入り、それ以外の$tall[0]~$tall[4]にはundefが入る。

$tall[5]=200;
@tall=(145.8,155.2);

このばあいには、最初の行で6個作成された配列が、次の行で2個になる。
$tall[0]=145.8
$tall[1]=155.2
$tall[1]以降の$tall[2]~$tall[5]は削除される。

@tall = (145.8,155.2);
$tall[5] = 200;

こうすると、一行目で作成された配列は6個に伸び@tallの中身は(145.8,155.2,undef,undef,undef,2000)となる。

| | コメント (0) | トラックバック (0)

2008年3月12日 (水)

「すぐわかるPerl」4.4 リストコンテキストとスカラーコンテキスト

■リストコンテキスト
以下のような場合、@tallは配列全体を現し、値はリストになる。
・リストに代入するとき

($suzuki,$satou,$johnny)=@tall;

・リストを代入するとき

@tall=($suzuki,$satou,$johnny);

・配列同士を代入するとき

@tall2=@tall;

■スカラーコンテキスト
以下のような場合、@tallは配列の要素数というひとつの数値になります。この文脈をスカラーコンテキストといいます。

  • スカラー変数に代入するとき
    $how_many = @tall;
  • 数値と比較するとき
    @tall > 0;
  • 数式の一部として扱うとき
    @tall + 1;

コンテキストによって挙動が異なるのは配列に限らない。
たとえば、print命令のばあい。

#! c:\perl\bin\perl.exe
# printarray -- 配列を印刷してみる

@tall = (145.8,155.2,180.2);
print @tall;
print "\n";

実行結果

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl"
145.8155.2180.2

次の場合は、スカラーコンテキスト(配列の数)となる。

#! c:\perl\bin\perl.exe
# printarray -- 配列を印刷してみる

@tall = (145.8,155.2,180.2);
$how_many = @tall;
print $how_many;
print "\n";

実行結果

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl"
3

@tallの中に3つの数が入っているので、3となる。

↓のばあいは、「@tall+0」という形で数式の一部として組み入れられるため、スカラーコンテキスト扱いになる。

#! c:\perl\bin\perl.exe
# printarray -- 配列を印刷してみる

@tall = (145.8,155.2,180.2);
print @tall+0;
print "\n";

実行結果

C:\Documents and Settings\sironekotoro>"C:\Documents and Settings\sironekotoro\デスクトップ\perl
test.pl"
3

| | コメント (0) | トラックバック (0)

2008年3月 7日 (金)

「すぐわかるPerl」4.3 ()を使ったリストと「@配列名」

そろそろ、blogのタイトル換えるとかしなきゃいけないんじゃないかと思う今日この頃。
皆さんいかがお過ごしでしょうか・・・

■リストと配列
リストは複数の値を持ったデータと考える事が出来る。
例)3人の人間の身長を145.8cm,155.2cm,180.2cmだとすると、これを
(145.8,155.2,180.2)
と書く事が出来る。

このリストを使って、配列を一気に初期化することが出来る。
配列全体を「@配列名」であらわす。

@tall=(145.8,155.2,180.2);

と書く事と

@tall[0]=145.8;
@tall[1]=155.2;
@tall[2]=180.2;

は同じ。

リストには変数も入れられる。

@tall=($suzuki,$satou,$johnny)

と書く事と

@tall[0]=$suzuki;
@tall[1]=$satou;
@tall[2]=$johnny;

は同じ。

リストに対して代入を行うことも出来る。

@tall=(145.8,155.2,180.2);
($suzuki,$satou,$johnny)=@tall;

この2行で
$suzukiに145.8が、$satouに155.2が、$johnnyに180.2がセットされる。
リスト同士の代入も可能。

$suzuki,$satou,$johnny)=(145.8,155.2,180.2);

■配列同士の代入
配列同士を代入する事も出来る

@tall=(145.8,155.2,180.2);
@tall2=@tall;

これは@tallの内容を@tall2にコピーするのと同じ。

@tall2[0]=@tall[0]; #つまり145.8が入る
@tall2[1]=@tall[1]; #つまり155.2が入る
@tall2[2]=@tall[2]; #つまり180.2が入る

リストの中にだ配列を入れることも出来る。この場合には、その場所で入れてうの中身がリストに展開されたのと同じ状況になる。

@tall=(145.8,155.2,180.2);
@tall2=(@tall,145.9,155.5,162.8);

これは↓と同じ。

@tall2[0]=@tall[0]; #つまり145.8が入る
@tall2[1]=@tall[1]; #つまり155.2が入る
@tall2[2]=@tall[2]; #つまり180.2が入る
@tall2[3]=145.9;
@tall2[4]=155.5;
@tall2[5]=180.2;

この原理で、配列の好きな位置に配列を挿入できる。

@tall=(145.8,155.2,180.2);
@tall2=(145.8,@tall,155.2,180.2);

この場合には、@tall2の1番目の要素($tall[0])の後に@tallが入る。
↓と同じ結果になる。

@tall2[0]=145.9;
@tall2[1]=@tall[0]; #つまり145.8が入る
@tall2[2]=@tall[1]; #つまり155.2が入る
@tall2[3]=@tall[2]; #つまり180.2が入る
@tall2[4]=155.5;
@tall2[5]=180.2;

末尾に入れれば末尾で展開される。

代入先のリストに配列を入れることもできる。

($johnny,@tall,$Bob)=(155.5,160,162.4,173,173.8);

$johnny=155.5;
@tail[0]=160;
@tail[1]=162.4;
@tail[2]=173;
@tail[3]=173.8;
$Bob=undef;

配列は伸び縮み自由であるため、残りの要素をすべて配列に収める。
このため、$Bobにはundefの値が入力される。

($johnny,$kate,@tail)=(155.5,160,162.4,173,173.8);

この場合には

$johnny=155.5;
$kate=160;
@tail[0]=162.4;
@tail[1]=173;
@tail[2]=173.8;

となる。

| | コメント (0) | トラックバック (0)

2008年2月28日 (木)

「すぐわかるPerl」4.2 配列変数の作成

変数同様、配列も事前の宣言なく利用が可能。
違うのは、インデックスを [ ] で囲んで指定する事。

$変数名 [インデックス]

#! c:\perl\bin\perl.exe
# avarage -- 平均身長を求める

$tall[0] = 155.5;
$tall[1] = 160;
$tall[2] = 162.4;
$tall[3] = 173;
$tall[4] = 173.8;
$tall[5] = 180.5;
$tall[6] = 178.2;
$tall[7] = 145.9;
$tall[8] = 155.5;
$tall[9] = 162.8;

$ave = ($tall[0] + $tall[1] + $tall[2] + $tall[3] + $tall[4] + $tall[5] + $tall[6] + $tall[7] + $tall[8] + $tall[9]) /10;

print "average:$ave\n"

これで10人の平均身長を求められるが、40人、50人と数が多くなると面倒。
そこで書き方を換えてみる。

#! c:\perl\bin\perl.exe
# avarage -- 平均身長を求める

@tall = (155.5, 160, 162.4, 173 , 173.8 ,180.5 ,178.2 ,145.9 ,155.5 ,162.8);

foreach $each_tall(@tall){
$sum += $each_tall;
}

$ave = $sum / @tall;

print "average:$ave\n"

新しく出てきた
・()を使ったリスト
・「@配列名」を使った配列変数の一括アクセス
・foreach
については次回。

| | コメント (0) | トラックバック (0)

2008年2月27日 (水)

「すぐわかるPerl」4.1 たくさんのデータを扱うときには

97Pより

たとえばクラスの身長を一人一人変数に入れたような場合、$tall1、$tall2というように変数を増やす代わりに、$tallという変数名(この場合、変数名はその変数のグループ名という感じになる)とインデックス(そのグループの何番目かを示す数字)によってデータを格納する変数を指定する。

このような変数を配列変数といいます。

配列・・・なんかどっかで聞いたことはあるけど、わからないなぁ。
あ、javascriptの勉強してたときに出てきたかも。
あれも身につかないまま放り出したままだったなぁ、そういえば。

| | コメント (0) | トラックバック (0)

2008年2月25日 (月)

「すぐわかるPerl」3.11 やっぱりforは紹介しておこう

for(最初に実行する文;ループを継続するか判定する文;ブロックの最後にやる分){
 命令1;
 命令2;
}

これをwhile文で書き換えるとこうなる
while(ループを継続するか判断する文){
 命令1
 命令2
 ブロックの最後に実行する文
}

#! c:\perl\bin\perl.exe
# power -- 階乗の計算(while版)

$n=10; #計算する数を変えるときはこの部分の数を変更
print "$n! == ";
$power = 1;
while($n > 1){
$power *= $n;
--$n;
}
print "$power\n";

これをfor文で書き換える

#! c:\perl\bin\perl.exe
# power -- 階乗の計算(for版)

$object=10; #計算する数を変えるときはこの部分の数を変更
print "$object! == ";

$power = 1;

for($n = $object; $n > 1; --$n){
$power * $n;
}

print "$power\n"

またはこうなる。

#! c:\perl\bin\perl.exe
# power -- 階乗の計算(for版)

$n=10; #計算する数を変えるときはこの部分の数を変更
print "$n! == ";

$power = 1;

for( ; $n > 1; --$n){
$power *= $n;
}

print "$power\n"

素数かどうかを調べるものを。

#! c:\perl\bin\perl.exe
# prime -- 素数かどうか調べる(while版)

$n=97; #調査する数を変える際はこの数字を変更
print "$n is ";

$div =2;

while($div <= ($n / 2)){
if (($n % $div) == 0){
  print "able to be divided by $div!\n";
  print "it's not ";
  last;
}
++$div;
}
print "a prime number!\n"

forで書き直す

#! c:\perl\bin\perl.exe
# prime -- 素数かどうか調べる(for版)

$n=97; #調査する数を変える際はこの数字を変更
print "$n is ";

for($div =2;$div <= ($n / 2);++$div){

if (($n % $div) == 0){
  print "able to be divided by $div!\n";
  print "it's not ";
  last;
}

}
print "a prime number!\n"

100以下の素数をリストアップ

#! c:\perl\bin\perl.exe
# prime100 -- 100以下の素数をリストアップする(for版)

for($n=2;$n <=100;++$n){
$prime=1;
for($div=2 ; $div <= ($n / 2); ++$div){
  if(($n % $div) ==0){
   $prime=0;
   last;
  }
}

if($prime){
  print "$n\n";
}
}

for文を使うメリットは
・ループ変数は何で、初期値は何か
・脱出条件は何か
・ループ変数をいくつかかウントアップ、またはカウントダウンするか

| | コメント (0) | トラックバック (0)

2008年2月22日 (金)

「すぐわかるPerl」3.10 紹介しきれなかった制御文

if,whileのほかの制御文
・unless(ifの反対)
・until(whileの反対、条件が偽の場合にループが回る)
・do{}while、do{}until(条件判定の前に一回はブロックを実行する)

lastのほかの制御文
・redo(ループでブロックの最初に飛ぶ)
・next(ループでブロックの最後に飛ぶ)

コンピュータ制御の進みは3つしかない。
・連結
・分岐
・繰り返し

| | コメント (0) | トラックバック (0)

2008年2月20日 (水)

「すぐわかるPerl」3.9 二重ループ

2~100の間にある素数の数を表示する。

#! c:\perl\bin\perl.exe
# prime100 -- 100以下の素数をリストアップする

$n = 2;

while ($n <=100){
$div = 2;
$prime = 1;

while($div <= ($n / 2)){
  if ($n % $div ==0){
   $prime = 0;
   last;
  }

  ++$div;
}

if($prime){
  print "$n\n";
}

++$n;
}

whileのなかにwhileを入れ子(ネスト)することで条件文を分岐させる。

・$nは調査対象の数であり、2から初めて100までカウントアップ
・$divは割る数であると同時に、内部のループのループ関数としても利用する。n/2までカウントアップ。

・$nが$divで割り切れたら($n % $div == 0)lastでループを抜ける
・ループを抜けた際、それが割り切れたからか、$divが$n/2を超えたからかを判定するため、$primeという変数を設定。
 primeが1だったら素数。primeが0だったら素数ではない。

| | コメント (0) | トラックバック (0)

2008年2月19日 (火)

「すぐわかるPerl」3.8 ifとwhileの複合技

■ある数が素数かどうかを調べる

#! c:\perl\bin\perl.exe
# prime -- 素数かどうか調べる

$n=97; #調査する数を変える際はこの数字を変更
print "$n is ";

$div =2;

while($div <= ($n / 2)){
if (($n % $div) == 0){
  print "able to be divided by $div!\n";
  print "it's not ";
  last;
}
++$div;
}
print "a prime number!\n"

実行結果

C:\Documents and Settings\sironekotoro>test.pl
97 is a prime number!

解説
ある数($n)の半分より大きい数字で割る事は出来ない。
whileループにはいる条件として、次々と数で割っていく($div)が、その限度はある数の半分までとする。

$nを半分に割った値が($n / 2)が2以下になるか?($div=2)

Yesならif文にて条件分岐。
  $nが2で割り切れるなら(割った余りが0なら)、「$divで割り切れる、」と表示。
  last文でif文を抜けてその下にあるブロックに移動して「~じゃない」

Noなら、$divに1を足してwhileループ

if文の条件を満たさなくなったらwhileループに入らず「素数は○○」と表示。


・・・解説の方がわかりにくいなぁ。
ソースのほうが読みやすい・・・。

| | コメント (0) | トラックバック (0)

2008年2月14日 (木)

「すぐわかるPerl」3.7 恐怖の無限ループ

前回作成した階乗を求めるプログラムを一部かえると無限ループになってしまう。

#! c:\perl\bin\perl.exe
# power -- 階乗の計算

$n=10; #計算する数を変えるときはこの部分の数を変更
print "$n! == ";
$power = 1;
while($n > 1){
$power *= $n;
#コメントアウト --$n;
}
print "$power\n";

$nから1をマイナスする部分がコメントアウトされる事で、無限ループとなる。
1.$nに10を入れる
2.$powerに1を入れる
3.while条件文に入る
4.$nは1より大きい
5.$powerに$n(つまり10)をかける
6.条件文中なので$nが1より大きいかどうかの判定に戻る。$nの数は10から変わっていないので、常にwhileループに入る。
以下、3~6の繰り返し。無限ループとなり、プログラムは終わらない。

while(1 == 2){
命令;
}
1は2で無いため、一度も実行されない。

while(1 == 1){
命令;
}
1は1なので、常にwhile条件式はyesになり、命令が繰り返される。

while(0){
命令;
}
命令は一度も実行されない。

while(1){
命令;
}
これは無限ループになる。

$aと3が等しい間ループさせたい場合。
while($a = =3){
命令;
}
と書かなければいけないが、

while($a = 3){
命令;
}
と書いてしまう(=がひとつ)と、$aに3が代入されるという意味合いになり、Whileの条件文が常にyesとなり、無限ループとなる。

同様に、$aが0の間はループする式を書こうとして
while($a = 0){
命令;
}
と、これまた同様に=を一つ少なく書いてしまうと、常に$aが0となりwhileでループしない。

| | コメント (0) | トラックバック (0)

「すぐわかるPerl」3.6 繰り返しの基本while

■階乗の計算

while(繰り返す条件){
命令1;
命令2;
・・・
}

例として、10の階乗を計算する。
・・・階乗って何?

階乗 - Wikipedia
http://ja.wikipedia.org/wiki/%E9%9A%8E%E4%B9%97
階乗(かいじょう)とは、自然数 n に対し、1 から n までの自然数の総乗を言う。これを n! と書く。

なるほど。
つか、そんな事も知らないのか自分・・・。
1からn(ここでは10)までの乗数だから、1×2×3×4×5×6×7×8×9×10を計算する、と。

#! c:\perl\bin\perl.exe
# power -- 階乗の計算

$n=10; #計算する数を変えるときはこの部分の数を変更
print "$n! == ";
$power = 1;
while($n > 1){
$power *= $n;
--$n;
}
print "$power\n";

実行結果

C:\Documents and Settings\sironekotoro>perl test.pl
10! == 3628800

■階乗プログラムの詳細
77P参照

10から始まって、1ずつ減っていく数を$nに、$nをかけていく値を$powerに入れる。

$n=10; #計算する数を変えるときはこの部分の数を変更
print "$n! == ";
$power = 1;

ここで$nと$powerを初期化。
次はループ部分。

while( $n > 1){
$power *= $n;
--$n;
}

$nは初期値が10なので、1より大きい。
$powerに$nをかけて、その値を$powerに代入する。
$nから1を引く
(*=、--については37Pか「すぐわかるPerl」2.6 他にも便利な演算子がある を参照)

このループを$nが1になるまで繰り返す。
$nが1になったとき、ループ部分の条件が偽となり、ループ部分の制御から抜ける。
最後に、$powerをprintして終了。

■条件を満たさない場合のwhile
whileの特徴は最初に条件を聞くこと。
条件を最初から満たしていない場合には、中身を実行しない。

0の階乗を求めた場合。

#! c:\perl\bin\perl.exe
# power -- 階乗の計算

$n=0; #計算する数を変えるときはこの部分の数を変更
print "$n! == ";
$power = 1;
while($n > 1){
$power *= $n;
--$n;
}
print "$power\n";

実行結果

C:\Documents and Settings\sironekotoro>perl perltest.pl"
0! == 1

| | コメント (0) | トラックバック (0)

2008年1月31日 (木)

「すぐわかるPerl」3.5 ()の中身はなんでもよい

■0と""が偽、それ以外は真
条件文の()の中身は、等式や不等式など以外に、普通の式や値を入れることも出来る。

if (0) {
命令;
}

実行されません

if (1) {
命令;


実行されます

if (2) {
命令;
}

実行されません

以上のように、条件式が0の場合には実行せず、0以外の場合には実行する。
理由は、perlでは0以外を「真」、0を「偽」とみなすため。
文字列の場合には、""(空文字列)を「偽」それ以外を「真」とする。

if (""){
命令;
}

実行されない

if ("a"){
命令;
}

実行される

if("" or 1){
命令
}

実行される

if(0 and "a"){
命令
]

実行されない

■複合条件の真偽
真をゼロ、偽をゼロ以外、orを足し算、andを掛け算と考えてみる。

if ((条件A) and (条件B) or (条件C)) {
命令;
}

Aが真、Bが偽、Cが真とする。
andを先に考えて「ゼロ」×「ゼロ以外」なので「(条件A) and (条件B)」はゼロ(偽)。
そのゼロと、条件Cの論理和は「ゼロ」+「ゼロ以外」なのでゼロ以外。

括弧を使ってorを先に結合させてみる。

if ((条件A) and ((条件B) or (条件C))) {
命令;
}

Aが真、Bが偽、Cが真とする。
括弧に入っている「(条件B) or (条件C)」から考える。ゼロ(偽)+ゼロ以外(真)なのでゼロ以外。
そのゼロ以外と条件A(ゼロ以外)の論理積はゼロ以外で真。
そのため、命令は実行される。

Aが偽、Bが真、Cが偽とした場合。
(条件B) or (条件C)=真(ゼロ以外)+ゼロ:ゼロ以外(真)
↑の結果と条件A(偽)=真(ゼロ以外)*偽(ゼロ)=ゼロ(偽)
この場合、命令は実行されない。

| | コメント (0) | トラックバック (0)

2007年12月26日 (水)

「すぐわかるPerl」3.4 文字列としての比較

■文字列が等しいかの判定は「eq」

$a="1";
$b="01";

$aと$bは数字として解釈すれば同じ。
しかし、文字列として解釈すれば別もの。
つまり、数字としては等しいが、文字列としては等しくない。

#! C:\Perl\bin\perl -w
# compare -- hikaku jikken

$a="1";
$b="01";

if ($a == $b) {
print "hitosii\n";
}else{
print "chigau\n";
}

実行結果

C:\Documents and Settings\sironekotoro\デスクトップ>perl hikaku.pl
hitosii

==は数字としての比較を行うため、$aと$bは等しいという結果になる。

文字列として比較する場合には「eq」という演算子を利用する。

#! C:\Perl\bin\perl -w
# compare -- hikaku jikken

$a="1";
$b="01";

if ($a eq $b) {
print "hitosii\n";
}else{
print "chigau\n";
}

C:\Documents and Settings\sironekotoro\デスクトップ>perl hikaku.pl
chigau

文字列として比較したため、「違う」と判断される。

先に出現する文字コードの大きいほうが大きくなる。
cap
cat
cup
dub

次の五つは小さい順に並んでいる。
aaa
aaaa
aaab
aaaaa
aaaab

次の四つのなかに、「10」を入れるとしたらどこになるか?
000
001
010
100

000
001
010
10
100

以上のことから「02」と「1」では、先頭の1文字を比較するため
"02" > "1"
となる。

$a="1";
$b="02";
では、数字としては$bが大きく、文字列としては$aが大きい。

文字列と数字を混合して並べた場合には、数字(0~9)より文字(a~z)の方が大きいと判断される。
100
1a0
1aa
a1a
aa1
aaa

■文字列の比較演算子

$x lt "a" $xが"a"より小さい (less than)
$x gt "a" $xが"a"より大きい (greater than)
$x le "a" $xが"a"以下 である(等しいかより小さい less than equal)
$x ge "a" $xが"a"以上 である(等しいかより大きい greater than equal)
$x eq "$y" $xと$yが等しい(equal)
$x ne "$y" $xと$yが等しくない(not equal)

[問題]
問題1
if "01" == "1" {
print "true";
}else {
print "false";
}

問題2
if "01" eq "1" {
print "true";
}else {
print "false";
}

問題3
if "01" <= "1" {
print "true";
}else {
print "false";
}

問題4
if "01" le "1" {
print "true";
}else {
print "false";
}

問題5
if "02" < "1" {
print "true";
}else {
print "false";
}

問題6
if "02" lt "1" {
print "true";
}else {
print "false";
}

回答
問題1:true
問題2:false
問題3:true
問題4:true
問題5:false
問題6:true

| | コメント (0) | トラックバック (0)

2007年12月11日 (火)

「すぐわかるPerl」3.3 「かつ(and)」と「または(or)」

■■「かつ」は論理積and
1.4で割り切れない年はうるう年ではない
2.4で割り切れkるとしは売る疎し
3.しかし、100で割り切れる年はうるう年ではない
4.しかし、400で割り切れる年はうるう年

この順番で書いた場合のスクリプトは間違い。なぜなら、1000などの100で割り切れる数もうるう年と判定してしまうため。

#! C:\Perl\bin\perl -w
# uruu -- うるう年判定(間違い)

$n = 1000;

if (($n % 4 ) != 0){
print "uruu doshi denai";
}elsif (($n % 4) ==0){
print "uruu dosi";
}elsif (($n % 100) == 0){
print "uruu dosi denai";
}else (($n % 400) == 0){
print "uruu doshi";
}

計算結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
uruu dosi

正しく式を構成するためには、下記のように考え直す。

1.4で割り切れない年はうるう年で無い
2.4で割り切れ、かつ100で割り切れない年はうるう年
3.100で割り切れ、かつ400で割り切れない年はうるう年でない
4.1~3いずれにも当てはまらないのはうるう年

「かつ」=二つ以上の条件が両方成立する場合。論理積。

#! C:\Perl\bin\perl -w
# uruu -- うるう年判定

$n = 2004;

if (($n % 4 ) != 0){
print "uruu doshi denai";
}elsif (($n % 4) ==0 and ($n % 100) != 0) {
print "uruu dosi";
}elsif (($n % 100) == 0 and ($n %400) == 0){
print "uruu dosi denai";
}else {
print "uruu doshi";
}

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
uruu dosi

「and」は == や != よりもゆるく結合するため、and以外の演算子を評価してから結合する。

■「または」は論理和or
うるう年の条件を更にまとめる。
1.「4で割れない年」または「100で割り切れ、かつ400で割り切れない年」はうるう年ではない。
2.1の条件に当てはまらない年はうるう年

if (($n % 4 ) != 0 or ($n % 100) =0 and ($n % 400) != 0 {
print "uruu de nai";
} else {
print "uruu dosi";
}

andはorよりも強く結合する。上記の式は
if(条件1) or ((条件2)and(条件3))

if ((条件A) and (条件B) or (条件C)){
命令;
}

条件A条件B条件C命令
実行される
× 実行される
× 実行される
× × 実行されない
× × 実行されない
× × 実行される
× × × 実行されない

まず、「A かつ B」という複合条件が成り立つかどうか、その後に「A かつ B」と「C」のどちらか一方、または両方が成り立つかどうかを考える。

and回路のor結合
if ((条件A) and ((条件B) or (条件C))){
命令;
}

条件A条件B条件C命令
実行される
× 実行される
× 実行される
× × 実行されない
× × 実行されない
× × 実行されない
× × × 実行されない

この場合には、「B または C」が成り立つかどうかを先に考え、その後に「B または C」と「A」が両方成り立つかを考える。

or回路のand結合

コレは後ほど。

| | コメント (0) | トラックバック (0)

2007年11月19日 (月)

車輪の再発明を恐れない

404 Blog Not Found:アマグラマーのすすめ - 美徳その2:短気
http://blog.livedoor.jp/dankogai/archives/50951049.html

車輪にしろネットにしろプログラミング言語にしろ、誰かが発明しておいてくれたからこそ使えるのです。アマグラマーは車輪の再発明を恐れないで下さい。誰でも最初は初心者で、そして誰もが何度も車輪を再発明しているのです。

うちがひそかに尊敬するdannkogaiさんのお言葉。
とっととCPANとかの使い方習った方が効率的なのかなーとか、いろいろ思い悩んでいたけど、まぁ、こつこつ地道にやっていってもいいよなぁ、と思いましたとさ。
大体、CPANって物自体があまりよくわからないし・・・

ちなみに、うちがperlを学ぶのはプログラマになりたいのではなく、自分の思うとおりのサービスを作るのに必要と思うから。
既存サービスの熟成を待つとか、お金払って作ってもらうってのもアリかも知れないけど、やはり自分のほしいものは自分で作るのが一番。
時間もお金も無いしねw

だからこそ、時間を掛けて、応用の利きそうなperlを一からコツコツと学んでいるわけです。

| | コメント (0) | トラックバック (0)

2007年11月 7日 (水)

「すぐわかるPerl」3.2 3分裂以上したい場合のelsif

■3つ以上の選択肢の場合
・ある数を3分割した場合のあまりを求めるプログラム

#! C:\Perl\bin\perl -w
# mod3 -- 奇数か偶数かを調べる

$n = 6; #奇数か偶数かを判定する数をここで設定
$amari = $n % 3;
if ($amari==0){
print "zero ";
} elsif ($amari==1){
print "ichi ";
} else {
print "ni ";
}
print "desu\n";

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
zero desu

elsif:上のif分が偽、かつelsifの後ろの条件が真の場合、それに続くブロックを実行する。

■ifだけで記述する方法
if文の中のif文に入れている。これをネスト、入れ子という。

#! C:\Perl\bin\perl -w
# mod3 -- 奇数か偶数かを調べる

$n = 5; #奇数か偶数かを判定する数をここで設定
$amari = $n % 3;
if ($amari==0){
print "zero ";
} else{
if ($amari==1){
print "ichi ";
}
else {
print "ni";
}
}
print "desu\n";

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
nidesu

書いてみるとこうなる。

if (条件文 1) {
条件文1が真のときに実行される命令1;
条件文1が真のときに実行される命令2;
} elseif(条件文 2){
条件文2が偽のときに実行される命令1;
条件文2が偽のときに実行される命令2;
} else{
条件が偽のときに実行される命令a;
条件が偽のときに実行される命令b;
}

■うるう年の判定
条件がたくさんある計算として、うるう年の計算が有名。

1.4で割り切れない年はうるう年ではない
2.4で割り切れるときはうるう年
3.しかし、100で割り切れる年はうるう年ではない
4.しかし、400で割り切れる年はうるう年

これを条件の範囲の大きい順に並べてみる
1>2>3>4

条件の厳しい順に並べるとこうなる
4>3>2>1

無謀ながら、ここまでを読んで自らでスクリプトを書いてみる

#! C:\Perl\bin\perl -w
# uruu -- うるう年判定

$year = 1700; #奇数か偶数かを判定する数をここで設定

$amari400=$year % 400;
$amari100=$year % 100;
$amari4=$year % 4;
if ($amari400==0){
print "$year ha uruu ";
}
elsif($amari100=0){
print "$year ha uruu de nai";
}
elsif($amari4=0){
print "$year ha uruu de nai";
}
else{
print "$year ha uruu de nai";
}
print "desu\n";

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
Found = in conditional, should be == at perlsample line 15.
Found = in conditional, should be == at perlsample line 12.
1700 ha uruu de naidesu

美しくは無いけど、どうだろうか。

#! C:\Perl\bin\perl -w
# uruu -- うるう年判定(教科書)

$n = 2007;

if (($n % 400 ) == 0){
print "uruu doshi";
}elsif(($n % 100 ) == 0){
print "uruu de nai";
}elsif (($n % 4 ) == 0) {
print "uruu dosi";
}else {
print "uruu de nai";
}

教科書のを見ると、関数が一個($n)だけですんでいる。
やはり、こうでないとなぁ。

| | コメント (0) | トラックバック (0)

2007年10月24日 (水)

「すぐわかるPerl」3.1 二股に分かれるif

■奇数か偶数かを判定するプログラム

奇数の場合

#! C:\Perl\bin\perl -w
# evenodd -- 奇数か偶数かを調べる

$n = 5; #奇数か偶数かを判定する数をここで設定
print "$n ha ";
$amari = $n % 2;
if ($amari==0){
print "guusuu";
} else {
print "kisuu";
}
print "desu\n";

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
5 ha kisuudesu

偶数の場合

#! C:\Perl\bin\perl -w
# evenodd -- 奇数か偶数かを調べる

$n = 6; #奇数か偶数かを判定する数をここで設定
print "$n ha ";
$amari = $n % 2;
if ($amari==0){
print "guusuu";
} else {
print "kisuu";
}
print "desu\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
6 ha guusuudesu

■条件文によって命令の実行が決まる

if (条件文) {
条件が真のときに実行される命令1;
条件が真のときに実行される命令2;
} else{
条件が偽のときに実行される命令a;
条件が偽のときに実行される命令b;
}

命令をブレース(brace){}で囲んでひとまとめにしたものをブロックと言います。
条件分が満たされない場合、偽(ギ)の場合はifのブロックの命令1,2は無視され、命令a,bが実行される。

■条件式
ここで条件と言うのは、普通、次のような等式や不等式であらわす条件式で書く。

$x < 4 $x が 4 より小さい
$x > 4 $x が 4 より大きい
$x <= 4 $x が 4 以下である
$x >= 4 $x が 4 以上である
$x == $y $x と $y が等しい
$x =! $y $x と 4y が等しくない

■elseブロックは省略できる
ifブロック及びelseブロックが空の場合でも問題なく実行は可能。

| | コメント (0) | トラックバック (0)

2007年10月23日 (火)

「すぐわかるPerl」2.12 スカラーと言う言葉を覚えておこう

数値や文字列などの、ひとつの値を保持する変数や、数値、文字列の事をスカラーと言います。

$pi = 3.141592650;
$name = "Hiroko"

この場合、$pi,3.141592650,$name,"Hiroko"はすべてスカラーとなる。

スカラーのうち、変数でないものを定数という。この場合は、3.141592650と"Hiroko"

スカラーとは値を一つ持つデータの事で、値を複数持つデータ配列やリストの形で表現が可能。

・スカラー:ひとつの値を保持する変数や数値、文字列
・スカラーのうち変数で無いもの:定数

| | コメント (0) | トラックバック (0)

2007年10月22日 (月)

「すぐわかるPerl」2.11 なぞの値undef

#! C:\Perl\bin\perl -w
# undefwhat -- 初期化されていない変数には何が入っているか?

$kotae = $nazo + 1;
print "$kotae\n"

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
Name "main::nazo" used only once: possible typo at perlsample line 4.
Use of uninitialized value in addition (+) at perlsample line 4.
1

初期化していない変数に1を足すと、答えが1になるので、変数の初期値は0と思われる。

文字列の場合には?

#! C:\Perl\bin\perl -w
# undefwhat -- 初期化されていない変数には何が入っているか?

$kotae = $nazo."hahaha";
print "$kotae\n"

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
Name "main::nazo" used only once: possible typo at perlsample line 4.
Use of uninitialized value in concatenation (.) or string at perlsample line 4.
hahaha

0hahaha(ゼロhahaha)にならないので、$nazoには""空(から)文字列が入っていたと考えられる。

初期化されていない変数はundef(undefined)で定義されている。そのため、
・数値としてみた場合には0として振る舞い
・文字列としてみた場合には""として振舞う

undefは個別に定義する事も出来る。

#! C:\Perl\bin\perl -w
# undefwhat -- 初期化されていない変数には何が入っているか?

$nazo=undef;
$kotae = $nazo."hahaha";
print "$kotae\n"

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
Use of uninitialized value in concatenation (.) or string at perlsample line 5.
hahaha

| | コメント (0) | トラックバック (0)

2007年10月19日 (金)

「すぐわかるPerl」2.10 文字列も変数に入る

#! C:\Perl\bin\perl
#!
$name = "hiroko";
print "My name is $name.\n"

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
My name is hiroko.

文字列を結合する演算子は「.」ピリオドで、このように使う。

$first_name = "Hiroko";
$last_name = "shimabukuro";
$full_name = $first_name." ".$last_name; #名前と苗字を1部ランク開けて結合
print "My name is $full_name.\n";

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
My name is Hiroko shimabukuro.

「=.」と言う演算子もある。文字列連結を行う。

#! C:\Perl\bin\perl -w
#!
$speed = "Hiroko";
$speed .= ",";
$speed .= "Eriko";
$speed .= ",";
$speed .= "Takako";
$speed .= ", and ";
$speed .= "Hitoe";
print "Speed are $speed.\n";

実行結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
Speed are Hiroko,Eriko,Takako, and Hitoe.

perlの性格として、「文字列と数値のどちらも変数に入れることが出来、適当に処理してくれる」と言うものがある。

#! C:\Perl\bin\perl -w
#!
$ninety_nine = "99";
$zero_zero = "00";
$point = ".";
print $ninety_nine + $zero_zero; #99+00
print "\n";
print $ninety_nine * $zero_zero; #99*00
print "\n";
print $ninety_nine.$zero_zero; #"99"."00"
print "\n";
print $ninety_nine.$point.$zero_zero; #"99"."."."00"
print "\n";

処理結果
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlsample
99
0
9900
99.00

| | コメント (0) | トラックバック (0)

2007年10月18日 (木)

「すぐわかるPerl」2.9 変数のスペルミスを防ぐには

「すぐわかるPerl」2.9 変数のスペルミスを防ぐには

■変数のスペルミスは怒られない
perlは変数を都度宣言する必要が無いため、文中で変数名を間違っても特にエラーは出ない。

#! C:\Perl\bin\perl
# calc -- party 宴会の割り算計算プログラム

$suzuki = 32000; #鈴木さんの出した金額
$satou = 12000; #佐藤さんの出した金額
$jonny = 4000; #ジョニーの出した金額
$atama =7; #合計人数

$ave = ($suzuki + $satou + $jonnny)/$atama; #一人当たりの平均 変数名を間違えている
print "average:$ave\n"; #平均額の表示

$suzuki -= $ave; #鈴木さんの出した金額から平均額を引く
$satou -= $ave; #佐藤さんの出した金額から平均額を引く
$jonny -= $ave; #ジョニーさんの出した金額から平均額を引く

print "return to suzuki:$suzuki\n"; #鈴木さんが支払う金額
print "return to satou:$satou\n"; #佐藤さんが支払う金額
print "return to jonny:$jonny\n"; #ジョニーさんが支払う金額

当然、正解とは異なります。

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
average:6857.14285714286
return to suzuki:25142.8571428571
return to satou:5142.85714285714
return to jonny:-2857.14285714286

■バグ発見には警告モードを使う
・perl -w、wはwarningの意

C:\Documents and Settings\sironekotoro\デスクトップ>perl -w perlcalc
Name "main::jonnny" used only once: possible typo at perlcalc line 9.
Use of uninitialized value in addition (+) at perlcalc line 9.
average:6285.71428571429
return to suzuki:25714.2857142857
return to satou:5714.28571428571
return to jonny:-2285.71428571429

と、警告が入る。

| | コメント (0) | トラックバック (0)

2007年10月17日 (水)

「すぐわかるPerl」2.8 変数を駆使した計算

考え方としては
・かかった金額を合計する
・頭数で割る。
・頭数で割った金額と、支払った額の差額を求める。

#! C:\Perl\bin\perl
# calc -- party 宴会の割り算計算プログラム

$suzuki = 32000; #鈴木さんの出した金額
$satou = 12000; #佐藤さんの出した金額
$jonny = 4000; #ジョニーの出した金額
$atama =7; #合計人数

$ave = ($suzuki + $satou + $jonny)/$atama; #一人当たりの平均
print "average:$ave\n"; #平均額の表示

$suzuki -= $ave; #鈴木さんの出した金額から平均額を引く
$satou -= $ave; #佐藤さんの出した金額から平均額を引く
$jonny -= $ave; #ジョニーさんの出した金額から平均額を引く

print "return to suzuki:$suzuki\n"; #鈴木さんが支払う金額
print "return to satou:$satou\n"; #佐藤さんが支払う金額
print "return to jonny:$jonny\n"; #ジョニーさんが支払う金額

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
average:6857.14285714286
return to suzuki:25142.8571428571
return to satou:5142.85714285714
return to jonny:-2857.14285714286

平均額(一人頭):約6857円
鈴木さん:25142円戻ってくる
佐藤さん:5142円戻ってくる
ジョニーさん:-2857円(追加で支払う)

| | コメント (0) | トラックバック (0)

「すぐわかるPerl」2.7 代入式は値を持つ

print 2+3;
print "\n";

$a = 2 + 3;
print $a;
print "\n";

は同じ結果になる。
これは、「2+3」という式が5という値を持っている事を意味する。

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
5

同様に、下の式も「$a=2+3」という式は$aに2+3を放り込むと言う事であり、「$a=2+3」という式そのものが5と言う値を持つ。

print $a = 2 + 3;
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
5

同様にこのようなことも出来る。

$a=$b=$c=5;
print "$a\n";
print "$b\n";
print "$c\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
5
5
5

代入演算子は右から処理されるため、まず、「$c=5」が実行される。
それとともに、「$c=5」という式が5という値を持つ。
「$c=5」が$bに入り、「$b=$c=5」という式が5と言う値を持ち・・・
最終的に、$a=$b=$cが一気に初期化できます。
一般的に、タ移入式は、計算結果と同じ値を持つと言える。

+=の場合。

$b=5;
$a=$b+=5;
print "$a\n";
print "$b\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
10
10

$b=+5はやはり計算結果と同じ値を持ちます。

++$aの式の値はどうなるでしょうか。

$a=5;
print ++$a
print "\n";
print $a;
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
6
6

つまり、++$aは$aに1を足し、計算した後と同じ値を持つ。

逆に、$a++にすると、結果が異なる

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$a=5;
print $a++;
print "\n";
print $a;
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
5
6

&a++は$aに1を足すが、計算する前と同じ値を持つ

| | コメント (0) | トラックバック (0)

2007年10月15日 (月)

「すぐわかるPerl」2.6 他にも便利な演算子がある

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$a = $a+10;
print "$a\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
10

aに数字を足す場合、$aを二回書くのを省略できる。

$a = $a + 10 と、$a += 10 と記述できる

演算子意味書き換えると
+= $a += 10; $aに10を足す $a = $a + 10;
-= $a -= 10; $aから10を引く $a = $a - 10;
*= $a *= 10; $aに10をかける $a = $a * 10;
/= $a /= 10; $aを10で割る $a = $a / 10;
**= $a **= 10; $aを10乗する $a = $a ** 10;
%= $a %= 10; $aを10で割った余りで$aを書き直す $a = $a % 10;

また、次の計算もよくある。

$a = $a + 1;

$aを1増やす。モノの数を数えたり、動作の回数を数えたりするなど。
1つ増やす事をインクリメントというので、これをインクリメント演算子と言う。

++$a;
$a++;

当然、ひとつ減らす計算もある。これはデクリメントと呼ばれる。

--$b;
$b--;

| | コメント (0) | トラックバック (0)

2007年10月11日 (木)

「すぐわかるPerl」2.5 電卓プログラムの進化~中学編~

「すぐわかるPerl」2.5 電卓プログラムの進化~中学編~

■変数とは
・perlでは変数の前に$をつける。$x,$yなど。
・C++やJavaと異なり、変数の宣言(変数名、データの種類、桁数など)を行う必要は無い。
・変数の宣言自体は可能なので行っても問題はない。

■変数に値を入れる
・$変数名 = 変数の値;
・ここで使われる = は、代入すると言う意味で、等しいと言う意味ではない。
 (等しいと言う意味の場合には==)

#! C:\Perl\bin\perl
$x=50;
print $x;

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
50

■二重引用符の変数展開

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$x = 50;
print "x:$x\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
x:50

$xの部分が$xの中身50として表示される。
つまり、二重引用符(")は変数を展開する。

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$x = 50;
print "x no nakami ha $x desuyo---\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
x no nakami ha 50 desuyo---

■変数にいろいろ代入してみる

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$x = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10;
print "x:$x\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
x:55

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$x = 2 * 2 * 2;
print "x:$x\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
x:8

式の内部に変数を利用する事も可能。

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$y = 100;
$x = 2/$y;
print "x:$x\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
x:0.02

■右辺の一部に左辺の変数を使う

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$x = 50;
$x = $x + 1;
print "x:$x\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
x:51

つまり $x=$x+1 の結果、$xに+1される。
コンピュータは = による代入に出会うと
1.右辺を計算して値を得る。
2.計算した値を=によって左辺に代入する。

つまり、1.の時点ではx=50、2.の時点でx=51 となる。

#! C:\Perl\bin\perl
# calc -- keisan program (hensuu hen)
$x = 100;
$x = 100 ** 100;
print "x:$x\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
x:1e+200

100の100乗、10の20乗であり、1のあとに0が20個つながった数字。
この表記方法を科学技術表示という。

| | コメント (0) | トラックバック (0)

2007年10月10日 (水)

「すぐわかるPerl」2.4 演算子のまとめ

+:足し算
-:引き算
*:掛け算
/:割り算

**:べき乗

#! C:\Perl\bin\perl
print 2**3;

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
8

%:剰余(割り算のあまり)

#! C:\Perl\bin\perl
print 11%3;

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
2

計算の順序は「掛け算、割り算、剰余」が「足し算、引き算」よりも優先される。
「掛け算、割り算、剰余」のなかでは、掛け算>割り算>剰余の順になる。

#! C:\Perl\bin\perl
print 2+3*5
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
17

#! C:\Perl\bin\perl
print ((2+3)*5);
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
25

#! C:\Perl\bin\perl
print 3*5**2;
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
75

平方根

#! C:\Perl\bin\perl
print sqrt(2);
C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
1.4142135623731

| | コメント (0) | トラックバック (0)

2007年10月 9日 (火)

「すぐわかるPerl」2.3 電卓プログラムの誕生

■数式の計算結果を表示させる

C:\Documents and Settings\sironekotoro\デスクトップ>perl
print "2+3*5\n";
^D
2+3*5

""で囲まない場合には、数式として処理される。

C:\Documents and Settings\sironekotoro\デスクトップ>perl
print 2+3*5;
print "\n";
^D
17

一行に数式と文字列を混ぜる事は出来ない。エラーが出る。

C:\Documents and Settings\sironekotoro\デスクトップ>perl
print 2+3+5"\n";
String found where operator expected at - line 1, near "5"\n""
        (Missing operator before "\n"?)
^D
syntax error at - line 1, near "5"\n""
Execution of - aborted due to compilation errors.

■便利な電卓プログラム
ex1)1次会で32000円、二次会で12000円、全員で8人。一人頭いくらか?

#! C:\Perl\bin\perl
print ((32000+12000)/8);
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
5500

計算式を

print (32000+12000)/8;
とすると、44000となり、/8が実行されないので注意する。
これは、printの直後に括弧が来た場合にその括弧の中だけをprintの引数と見るため、/8の部分が捨てられる事による。

print文の直後に括弧が無いパターン1

#! C:\Perl\bin\perl
print 1/7*(32000+12000+4000);
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
6857.14285714286

print文の直後に括弧の無いパターンその2

#! C:\Perl\bin\perl
print 1*(32000+12000+4000)/7;
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
6857.14285714286

print文の直後に括弧があるパターン(末尾の/7が実行されてない)

#! C:\Perl\bin\perl
print (32000+12000+4000)/7;
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
48000

ex2)1次会で32000円、二次会で12000円、二次会のビール代が4000円。全員で8人。一人頭いくらか?

#! C:\Perl\bin\perl
print ((32000+12000+4000)/8);
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
6000

print文の直後であっても、-二重括弧にする事で正常な計算が可能になっている。

ex3)1次会で32000円、二次会で12000円、二次会のビール代が4000円。全員で8人。うち1名の送別会。主役は無料。一人頭いくらか?

#! C:\Perl\bin\perl
print ((32000+12000+4000)/7);
print "\n";

C:\Documents and Settings\sironekotoro\デスクトップ>perl perlcalc
6857.14285714286

| | コメント (0) | トラックバック (0)

2007年9月30日 (日)

「すぐわかるPerl」2.2 Printで遊んでみよう

Microsoft Virtial PC2007にfedora core6をいれて、そこでperlを動かしてます。
こちらの方がviとかを使える(学べる)分、良いかもしれないですね。

printで出力するとき、文字列のみであれば()は不要となる。

[sironekotoro@localhost perl-study]$ cat flashy
#! /usr/bin/perl
# flashy -- 派手な挨拶のプログラム
print "************************************************\n";
print "*** hello! Welcome! to the perl World!(^-^) ****\n";
print "************************************************\n";

[sironekotoro@localhost perl-study]$ perl flashy
************************************************
*** hello! Welcome! to the perl World!(^-^) ****
************************************************

一個のprint命令で出力してみた場合。冗長だけど、結果は同じ。

[sironekotoro@localhost perl-study]$ cat flashy-long
#! /usr/bin/perl
# flashy -- 派手な挨拶のプログラム
print "************************************************\n*** hello! Welcome! to the perl World!(^-^) ****\n************************************************\n";

[sironekotoro@localhost perl-study]$ perl flashy-long
************************************************
*** hello! Welcome! to the perl World!(^-^) ****
************************************************

改行は\nという特殊文字によって行われる。
\tはタブの挿入。

[sironekotoro@localhost perl-study]$ perl
print "L\n\tL\n\t\tL\n\t\t\tL\n";
L
        L
                L
                        L

print文で分けても同じ表現になる。

[sironekotoro@localhost perl-study]$ perl
print "L\n";
print "\tL\n";
print "\t\tL\n";
print "\t\t\tL\n";
L
        L
                L
                        L

| | コメント (0) | トラックバック (0)

「すぐわかるPerl」2.1 プログラムのリサイクル

■プログラムの一部を変えるには

#! /usr/bin/perl
# hello -- 挨拶のプログラム
print ("hello!\n");

プログラムファイルをコピーし、コピーしたものの一部を変更して、表示される文面を変える。

#! /usr/bin/perl
# goodbye -- 挨拶のプログラム
print ("goodbye...!\n");

■プログラム使いまわしのポイント
・似たような機能を実現するとき、教科書を調べなおす必要が無い。
・タイプミスの可能性が減る

| | コメント (0) | トラックバック (0)

2007年9月28日 (金)

「すぐわかるPerl」第一章のまとめ

  • 「perl -v」 でバージョンを調べる。
  • 「perl(改行)」で標準入力からプログラムを受け付ける。^D([CTRL]+[D])で終了。
  • 「perl ファイル名」でファイルを読み込んで実行
  • #!でコマンド化出来る。
  • 文字列を出力する命令は print
     print () で。()の中に文字や数式を入れる。
  • ""で文字列を渡す。むき出しで渡すと計算結果が出力される。
     print("1+2")だと、結果は1+2
     print(1+2)だと、結果は3
  • \nは改行
  • 各命令は;で終わる。
  • 注釈は#から行末まで

| | コメント (0) | トラックバック (0)

「すぐわかるPerl」1.5 魔法の呪文#!

■#!コマンドを作る(Unixのみ)

#! /usr/local/bin/perl

ファイルcalcの全体像は次のようになります。

#! /usr/local/bin/perl
# calc -- 計算のプログラム
print ("1 + 2 = ");
print (1 + 2);
print ("\n"); # 改行

#! /usr/local/bin/perl 以下のスクリプトを /usr/local/bin/perl で実行。
unixの場合にはchmodで実行権限を与える。

chmod a+x calc

以上により、プログラムファイル(この場合はcalc)がコマンド化する。

■ファイル名でプログラムを実行する。

calc

で実行が可能。

| | コメント (0) | トラックバック (0)

2007年9月27日 (木)

「すぐわかるPerl」1.4 perlの命令をファイルに書く

■Emacsにはまろう!
Emacsを進めているけど、さすがに敷居が高いと言うか・・・
使いこなしている人はかっこよいのだけどねぇ・・・うむー

■プログラムを保存する
プログラム中にコメントを入れるためには#を利用する。#以降はその行の終わりまでがコメント扱いとなる。

# calc -- 計算のプログラム
print ("1 + 2 = ");
print (1 + 2);
print ("\n"); # 改行

calcというファイル名で保存。

■プログラムを実行する

C:\Documents and Settings\sironekotoro>perl calc
1 + 2 = 3
C:\Documents and Settings\sironekotoro>

中身の数式を変えて保存

# calc -- 計算のプログラム
print ("3 * 2 = ");
print (3 * 2);
print ("\n"); # 改行

C:\Documents and Settings\sironekotoro>perl calc
3 * 2 = 6
C:\Documents and Settings\sironekotoro>

| | コメント (0) | トラックバック (0)

2007年9月20日 (木)

「すぐわかるPerl」1.1~1.2

「すぐわかるPerl 初版 第3刷」を参考に。
とまっていた勉強を再開。

Perlのインストール。
ActiveState - Download ActiveState ActivePerl
http://www.activestate.com/store/download.aspx?prdGUID=81fbce82-6bd5-49bc-a915-08d58c2648ca

C:\Documents and Settings\sironekotoro>perl -v

This is perl, v5.8.8 built for MSWin32-x86-multi-thread
(with 18 registered patches, see perl -V for more detail)

Copyright 1987-2007, Larry Wall

Binary build 822 [280952] provided by ActiveState http://www.ActiveState.com
Built Jul 31 2007 19:34:48

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

| | コメント (0) | トラックバック (0)