|  |
1 Perlの動かし方
2 簡単な計算
3 繰り返し
4 入力
5 関数定義
6 コメント
7 デフォルトの対象
8 ダイヤモンド
9 文字列の書き方
10 正規表現
11 文字クラス
12 UNIXの常識
13 パターンマッチ
14 $&($MATCH)について
15 例題
16 マッチした文字列を置き換える
17 さらに正規表現
18 配列
19 ダブルクオートでの展開
20 スカラーコンテキストとリストコンテキスト
21 要素
22 配列操作
23 並べ替え
24 連想配列
25 例題
26 制御構造と関数
27 UNIXの機能
1 Perlの動かし方
Hello,worldとプリンとします。
print("Hello,world\n");
以上です。
main()とか#include とかの呪文は全くいりません。
文字列はダブルクオーテーション「"」で囲みます。
「\n」は改行の意味です。
printはprintfではなくprintです。
perl+ファイル名で保存します。
例えば
perl hello.perl
です。
でも ファイルの先頭に
#!/usr/local/bin/perl
とか
#!/usr/bin/perl
と入れるとファイル名だけで実行できます。
だから
hello.perl
のファイル名でよいわけです。
*************************************************************************************
2 簡単な計算
print(1+2)*3,"\n";
の実行結果は9ではなく3がプリントされます。
(1+2)の部分が引き数として解釈されてしまうからです。
この場合は
print((1+2)*3,"\n)";
とすると9が表示されます。
括弧は大切です。気をつけましょう。
1万円を年6%の利率で預けると1年後にいくらになっているかを計算するプログラム
$zandaka = 10000;
$riritsu = 6;
$zandaka *=(1+$riritsu/100);
$print"zandaka = $zandaka\n";
となります。
$zandakaと$riritsuは変数です。
変数の前には$がつくことを覚えましょう。
ほかにもいろいろありますけど・・・・
実行結果は
zandaka = 10600
となります。
$zandaka *=(1+$riritsu/100);
の *= の意味は
$zandaka = $zandaka * (1+$riritsu/100);
という意味になります。
$print"zandaka = $zandaka\n";
は変数展開と言って
"zandaka = 10600\n"
の意味になります。
perlは変数を宣言せずに使うことが出来ます。
cの様にint,doubleなどの関数を必要としません。
perlの計算は基本的に全て浮動小数点で計算されることも大切です。
では整数計算の場合はどうなるのでしょうか?
$i = 6/100;
print"$i\n";
を実行すると
0.06となります。perlは基本的に浮動小数点表示です。
整数計算にするには整数計算したい部分を
use integer; と no interger;
で囲みます。
例えば
use interger;
$i = 6/100;
print"$i\n";
no integer;
$i = 6/100;
print"$i\n"
となります。
実行結果は
0
0.06
となり前半は整数計算になっています。
*************************************************************************************
3 繰り返し
$zandaka *= (1 + $riritsu/100);
$zandaka *= (1 + $riritsu/100);
$zandaka *= (1 + $riritsu/100);
と書くと3年分計算できます。
でも面倒くさいです。
そんなときは
$zandaka = 10000;
$riritsu = 6;
$nen = 10;
for ($i =; $i<$nen; $i++){
$zandaka *= (1 + $riritsu/100);
}
print"zandaka = $zandaka\n";
となります。
それも10年分の計算が出来てしまいました。
実行すると
zandaka = 17908.4769645285
となります。
一年で7908円増えることが解ります。やったー
*************************************************************************************
4 入力
では
元金(最初の残高)、利率、年数を入力できるようにしてみましょう。
print"zandaka?";
$zandaka = <stdin>
print"riritsu?";
$riritsu = <stdin>
print "nen?";
$nen = <stdin>
for ($i = 0; $i < $nen; $i++){
$zandaka *= (1+ $riritsu/100);
}
print"zandaka = $zandaka\n"
となります。
まず 画面に
zandaka?
と出ます。
残高をキーボード入力します。
その入力した値は<stdin>に返されます。(しまう事ね)
その後
riritsu?
と画面表示されます。
同じようにキーボード入力します。
その値は$riritsuの中の<stdin>にしまわれます。
次に
nen?
と表示されてまたまたキーボード入力します。
その値は$nenの<stdin>にしまわれます。
for ($i = 0; $i < $nen; $i++)
の部分でiの値を0に初期化して$i++でインクリメントします。
計算結果は例えば
zandaka? 10000
riritsu? 0.5
nen? 10
zandaka = 10511.4013204079
となります。
10年たっても511円しか増えません。
使ってしまいましょう。<笑>
ここで解るように$rirtsuの中には文字列もしくは数が入っています。
どっちなんでしょう?
画面入力された文字列が後になって計算式の中に組み込まれています。
Cの時なら
scanf() atoi()などで文字列から数に変換して
printf()などで数から文字列に変換すると言う処理をいちいち書かないといけませんでした。
perlはみんな自動的にやってくれます。
便利だねー
perlは必要に応じて変換してくれます。
でも 比較するときはどうするのでしょうか?
$x ="0.0";
$y ="0";
と言う文字列は同じではありません。
でも数としては同じ0です。
== と eq を使います。
例えば
$x == $y は同じですが、
$x eq $y は偽となります。
== は 数を比較するときに
eq は 文字列を比較するときに使います。
こんなプログラムの意味は解りますか?
$one = 1;
$two = 2;
$x = "$one$two.$one";
$y = $x * 2;
print"$y\n";
$xには12.1が代入されます。
$yには12.1 * 2の計算結果が代入されます。
よって
$yには24.2が代入され表示されます。
なんだそりゃ・・・
*************************************************************************************
5 関数定義
利率が何%であれば10年で貯金が倍増するかを調べるプログラムは
どうするのでしょうか?
考え方としてはまず利率を1%にして10年後の残高を計算します。
その利率で倍になっていなければ利率を2%にします。
倍になっていればその結果を表示します。
要するに利率が何%ならば10年後に貯金が倍になるかというプログラムです。
$riritsu = 1;
while(zandaka(10000,$riritsu,10)<20000){
$riritsu++;
}
print"$riritsu % nara 10 nen de baizoushityaimasu yatta-.\n";
となります。
ここではforでなく whileを使ってみました。
元金を10000円にして10年後に20000円にならないうちは
ずーっとループして20000円以上になったらwhile loopを抜けて結果を表示します。
では関数定義の仕方ですが、subを使って書きます。
sub zandaka{
my($zandaka,$riritsu,$nen) = @_;
my($i);
for($i = 0; $i < $nen; $i++){
$zandaka *=(1 + $riritsu/100);
}
return $zandaka;
}
となります。
subの次に関数名を書きその後ろに{}で囲みます。
zandakaと$zandakaは$がついているかいないかを
perlが判断するので関数名と変数名は同じでも構いません。
ところで @_ と言う怪しげなマークはなんでしょう?
ふつうの変数には $ がつきました。
@_ は いくつもの変数が入るときに配列変数のことを表します。
$zandaka $riritsu, $nen が順番に格納されます。
myはそのブロックのローカル変数を作っています。
結局この行を実行すると1つ目の引き数がローカル変数$zandakaに代入され
同時に2つ目、3つ目の引き数がそれぞれローカル変数$riritsu,$nenに代入されます。
my($i) はなんでしょう?
perlでは $i をグローバル変数からローカル変数に変換します。
*************************************************************************************
6 コメント
コメントの書き方に良い悪いは無いのですけど
基本的にコメントが無くてもわかりやすいプログラムがよいとされています。
でも やっぱり書きたいときもあるのでそんなときは perlでは
# を使います。
この#は行の終わりまで生かされます。
#このプログラムは解ったかな?
sub zandaka{
my($zandaka,$riritsu,$nen) = @_;
my($i); #ローカル変数に変換
for($i = 0; $i < $nen; $i++){
$zandaka *=(1 + $riritsu/100);
}
return $zandaka;
と言う感じです。
*************************************************************************************
7 デフォルトの対象
先ほど @_が出てきましたが、$と@は全く別の変数になります。
@は配列変数で
$はスカラー変数と言います。
$_はたいていの組み込み関数で操作対象を指定していない場合は
デフォルトで $_となります。例えば
print
の場合は
print$_;
の意味になります。
またwhileの条件の部分にキーボード入力演算子<stdin>を書き込むと
自動的に$_がセットされます。<stdin>以外のものが書いてあるとセットされません。
例えば
while(<stdin>){
print;
}
の文は
while($_=<stdin>){
print$_;
}
の意味と同じになります。
$_を活用するとプログラムがコンパクトになります。
*************************************************************************************
8 ダイヤモンド
キーボード入力の演算子は<stdin>だと書きましたが実際には<stdin>よりは
<> の方がよく使われます。
<> はダイヤモンド演算子と呼ばれています。
unixでは引き数にファイル名を指定するとそのファイル名から入力する。
ファイル名を複数指定すると順番に入力していきます。
ファイル名の指定のない場合は標準入力から入力する。と言う動作になります。
<>は自動的にやってくれます。
while(<>){
print;
}
このプログラムはwhileの条件の部分に<>だけを書くと$_に自動的に代入されます。
file1を指定するとfile1の内容がプリントされます。
file1とfile2を指定すると順番にそれぞれがプリントされます。
ファイル名を指定しなければ標準入力から読み込んだものをプリントします。
<stdin>を使うと標準入力からしか読めませんが、<>を使うと
標準入力からもファイルからも読めるようになります。
<stdin>よりも<>の方が多く使われます。
*************************************************************************
9 文字列の書き方
********************
とりあえずはダブルクオートが基本です。
例えば
The width is 100
と 出力したかったら
Print"The width is 100cm.\n";
と書くだけです。
100の部分を代入することがあれば
こんな記述をしておくとよいです。
$width=100;
print"The width is ${width}cm.\n";
そうすると${}はなに?と思うでしょ。
これは $は変数だよと言う意味です。
だから $widthという変数に100という数を代入するよ
と言う意味になります。だったら
print"The width is widthcm.\n";
でいいんじゃないの?と思うかもしれませんが
perlは おっ widthcm と言う変数かな?と解釈してしまいます。
だから 変数の部分に ${} をつけてちゃんと区別できるように
してあるわけです。
perlにはこんなスイッチもあります。
\u から \e迄の文字を大文字にします。
\u だけ記述するとその部分の文字の頭が大文字になります。
例えば
$name = "suzuki";
print"My name is \u$name.\n";
print"\u$name\e is my name.\n";
これを実行すると
My name is Suzuki.
SUZUKI is my name.
となります。
便利なのかな?・・・・・
変数の名前や($xとか)改行のマーク(エスケープシーケンスという)を
表示したいときは \ を入れるとうまくいきます。
例えば
print"The variable is \$x.\n";
print"\\n is a newline.\n";
これを実行すると
The variable is $x.
\n is a newline.
となります。
これも便利なのかな?・・・・
ううーん?_
******************************************************************************************
11 正規表現
*************************
正規表現とはパターンを書くときの表記法のことをいいます。
例えば
正規表現 マッチする文字列
suzuki "suzuki"
suzuki*n "suzukn""suzukiin""suzukiiin""suzukiiiin"
suzu(ki)* "suzu""suzuuki""suzukiki""suzukikiki""suzukikikiki"
suzu(ki)+ "suzuki""suzukiki""suzukikiki""suzukikikiki"
となります。
suzuki*n はsuzukの後の iが何回か続いてその次にnがあるような文字列とマッチします。
結局 * は何回か続いてと言う意味があります。
suzu(ki)*は()の中の部分を繰り返して・・・と言う意味です。
だから
suzu suzuki suzukiki suzukikiki とかになります。
+も繰り返しのメタ文字です。
*とか+とかをメタ文字と言います。
+は 一回以上の繰り返しを意味します。
suzuki suzukiki suzukikiki とかね・・・
aの次にbが何個かある
と言う場合に
ab*
と書くと
* は0回以上だからbが無くてもマッチしてしまいます。
a だけでもマッチすることになります。
そういうときは
ab+
とすると
ab abb abbb abbbb などがマッチします。
次に または〜
と言うときに使うのが | です。
ms-dosのときにパイプとかいっていたものと同じですけど
意味が全然違います。
suzuki|satou
だと suzuki又はsatouでマッチします。
(suzuki|satou)(haruna|katano) にすると
suzuki又はsatouの次にharuna又はkatanoが続くような文字列とマッチします。
suzuki haruna suzuki katano satou haruna satou katano
と言う4通りの組み合わせがあります。
()をとってしまうと
suzuki|satou|haruna|katano にしてしまうと
suzuki又はsatou又はharuna又はkatanoという意味になってしまいます。
これらを組み合わせると 複雑な組み合わせが出来ます。
例えば
(suzuki|satou)*
にすると
suzuki又はsatouが0回以上繰り返すという意味になります。
0回なら ""とマッチします。
1回なら "suzuki" "satou"
2回なら "suzukisuzuki" "satousatou" "suzukisatou" "satousuzuki"
の4通りになります。
********************************
******************************************************************************************
11 文字クラス
*******************
英字で始まる英数字の列
と言うようなパターンを表したい場合には、まず「英字」とか「英数字」とかを
表す必要があります。
「数字」の場合はどうなるのでしょう?
(1|2|3|4|5|6|7|8|9|0)
となります。
英字の場合は・・・・・・
面倒くさいので書きません・・・
でもこんな風に書くこともできます。
[1234567890]
となります。
もっと簡単に書くことが出来ます。
[0-9]
です。
これなら簡単!!
英文字の場合は
[a-zA-Z]
となります。
英文字と英数字の場合は
[a-zA-Z0-9]
となります。
英語の大文字で始まる4桁の英数字の場合は
[A-Z][0-9]*
となります。
〜以外と言う書き方はどうするんでしょう?
文字クラスの前に ^ を書くと〜以外と言う意味になります。
[^abc] abc以外の1文字
[^0-9] 数字以外の1文字
perlでは こんなスイッチが用意されています。
\d 数字 [0-9]と同じ
\D 数字以外 [^0-9]と同じ
\w 英数字(_も含む) [_a-zA-Z0-9]と同じ
\W 英数字以外 [^_a-zA-Z0-9]と同じ
\s 空白文字(スペース、タブ、改行など) [\t\n\x11\f\r]と同じ
\S 空白文字以外 [^\t\n\x11\f\r]と同じ
たとえば
(0|1|2|3|4|5|6|7|8|9|)+
[0123456789]+
[0-9]+
\d+
とみーんな同じ意味になります。
***********************************************
***********************************************************************
12 UNIXの常識
********************
perlやUNIXの中でよく使われるコマンドをここでは常識であると言う意味で
UNIXの常識と書きますが 本当はもっとたくさんあってとても覚え切れません。
簡単なものから、よく使われるものから順番に覚えていきましょう。
\ エスケープシーケンス
^ 行(文字列)の先頭
$ 行(文字列)の最後
. 任意の1文字(改行を除く)
[] 文字クラス
* 0回以上繰り返し
+ 1回以上繰り返し
? 0回か1回か
| または
() グループを作る
\にはメタ文字の意味をなくすという働きもあります。
\* と書けば * はメタ文字ではなく、*という文字自体になります。
例えば
\** と書くと 0個以上の*とマッチします。
^は行(文字列)の先頭にマッチします。
$は最後にマッチします。
^$ と書けばから行にマッチします。
.(ピリオド)は改行以外の任意の1文字とマッチします。その部分は何でもよいという
場合に使われます。
*************************************************************************************
13 パターンマッチ
***********************
文字列が正規表現にマッチするかどうかを調べることをパターンマッチと言います。
変数$str に入っている文字列と正規表現のパターンマッチは次のように書きます。
$str=~/[a-z]+/
正規表現を \ で囲んで書き、調べたい変数と =~ でつなげます。
=~ の~(チルダ) を忘れたり、=と~の間にスペースを入れてはいけません。
変数 =~ /正規表現/ を実行すると変数の中の文字列と正規表現がマッチするかどうかの
真偽値を返します。
普通はifをつかいます。
if($str=~/[a-z]+/){
print"matc\n";
}else{
print"notmatch\n";
}
=~の代わりに!~を使うとマッチしないかどうかを調べることが出来ます。
変数=~の部分を省略して /正規表現/ だけを書くと$_ を指定したことになります。
ダイヤモンド演算子 <> を書くと入力した行が自動的に $_ にはいるのでそれと組み合わせると
便利です。
while(<>){
if(/[a-z]+/){
print"match\n";
}else{
print"notmatch\n";
}
}
の様になります。
実行すると
abc (ユーザーの入力)
match
012 (ユーザーの入力)
nomatch
012a (ユーザーの入力)
match
となります。
[a-z]+ は 1文字以上のアルファベットとマッチします。
012a は 対象の文字列の中にどこか一部分でもマッチする部分があればマッチしたことになります。
こんな使い方もあります。
/[a-z]+/ 文字列の中に[a-z]+ にマッチする部分があるか
/^[a-z]+/ 文字列が[a-z]+ で始まっているか
/[a-z]+$/ 文字列が[a-z]+ で終わっているか
/^[a-z]+$/ 文字列全体が [a-z]+にマッチしているか
です。
ところでこんなのはどうでしょう?
$` マッチした部分より前
$& マッチした部分
$' マッチした部分より後ろ
これは
while(<>){
chomp;
if(/[a-z]+/){
print"<$`><$&<>$'>\n";
}else{
print"not match\n";
}
}
と言う例で考えてみましょう?
最初のchomp; は $_の中の最後の改行を取り除く組み込み関数です。
$_ の最後に改行がついていると、$' にも最後に改行が入ってしまい、プリント
しにくくなるので最初に取り除くことを表します。
「最初に chomp した?」
とかいいます。
実行すると、
012abc345 ユーザーの入力
<012><abc><345>
abc ユーザーの入力
<><abc><>
abc012def ユーザーの入力
<><abc><012def>
となります。
正規表現は [abc]+ なのでabc の部分にマッチします。
マッチしたabcは真ん中のabcの部分にマッチします。
マッチしたabcは$&に代入されます。
マッチした部分の前の012は&`に代入されます。
マッチした部分より後ろの345は$'に代入されます。
abc012def は両方ともアルファベットなのに・・・
これは 最初の方がマッチすることが解ります。
ちなみに英語で書くこともできます。
いやいや パールは親切だね・・・
use English;
while(<>){
chomp;
if(/[a-z]+/){
print"<$prematch><$match><$postmatch>\n";
}else{
print"not match\n";
}
}
*********************************************************************************
14 $&($MATCH)について
*************************
$&($match)は正規表現にマッチした部分を全部取り出します。
マッチした部分全部ではなく、その一部を取り出すことも出来ます。
そのためには正規表現の中の取り出したい部分を () で囲みます。
例えば次の正規表現は、小文字が1文字以上有り、:が有り
任意の文字が0文字以上あるという意味です。
"name:Suzuki"の様にキーと値を:で区切ったような文字列にマッチします。
[a-z]+:.*
この:野前のキーボブ分と後の値の部分を取り出したい場合は、その部分を()で囲みます。
([a-z]+):(.*)
()で囲んだ部分は前から順番に$1,$2,......と言う特別な変数に代入されます。
例えば
while(<>){
chomp;
if(/([a-z]+):(.*)/){
print"key=$1,value=$2\n";
}else{
print"not match\n";
}
}
実行すると
name:Suzuki ユーザー入力
key=name,value=Suzuki
age:4 ユーザー入力
key=age,value=4
となります。
()が何十にもなっているときは括弧の順番に数えていきます。
(([a-z]+):(.*))
となっていれば 順番に $1,$2,$3と値が入ります。
***********************************************
*************************************************************************************:
15 例題
****************
UNIXのwcコマンドは行数、単語数、バイト数、ファイル名をプリントします。
wcの出力から行数と単語数を取り出し1行あたりの平均単語数を計算するプログラムを
考えます。
while(<>){
chomp;
print$_;
if(/(\d+)\s+(\d+)/){
$line=$1;
$word=$2;
$words_per_line=$word$/$line;
printf("\t%.2f words/line",$words_per_line);
}
print"\n";
}
正規方言で最初の数(行数)と次の数(単語数)を取り出し、$lineと$wordに代入します。
取り出したのは文字列ですが自動的に数に変換されるのでそのまま式の中で使えます。
1行あたりの単語数を計算したら、それをプリントします。
小数点以下第2位までの形式でプリントするためにprintfを使っています。
実行すると
77 238 1683 perl5.003/embed.pl 3.09 words/line
270 307 2170 perl5.003/keywords.pl 1.14 words/line
137 439 3207 perl5.003/minimod.pl 3.20 words/line
648 2544 15613 perl5.003/opcode.pl 3.93 words/line
1132 3528 22673 total 3.12 words/line
となります。
************************************************************************
英語の名詞を入力するとその複数形をプリントするプログラムを作ってみます。
複数形を作る規則は簡単に次の規則になると思います。
1 sで終わる名詞はesをつける
2 子音とyで終わっている名詞はyをiに変えてesをつける
3 その他はsをつける
プログラムを簡単にするために単語のみを入力し前後によけいな文字は入力しないものとします。
use English;
while(<>){
chomp;
if(/s$/){
print$_,"es\n";
}elsif(/[^aiueo])y$/){
print$prematch,$1,"ies\n";
}else{
print$_,"s\n";
}
}
まず、「/s$/」でs で終わっているかを調べます。
s で終わっていたら、入力された単語とes をプリントします。
子音はaiueo以外ということにします。
そうすると「/(^aiueo]y$/」で子音とyで終わっているかどうかが調べられます。
この場合はyで終わっているかどうかが調べられます。
この場合はyの前までをプリントしてiesをプリントします。
yの前までプリントするには $prematch と $1をプリントすればOKです。
実行すると
bus ユーザー入力
buses
city ユーザー入力
cities
boy ユーザー入力
boys
book ユーザー入力
books
となります。
*********************************
****************************************************************************************
16 マッチした文字列を置き換える
**********************************
マッチするかどうか調べるだけではなく、マッチした部分を別の文字列に
置き換える事も出来ます。
置き換えるには
s/正規表現/置き換える文字列/
を使います。
sはsubustituteの意味です。
例えば
$str=~s/\s+/ /;
は、$strの中の1個以上の空白文字を一つのスペースに置き換えるものです。
変数を省略すると例によって、$_の値を置き換えることになります。
ダイヤモンド演算子と組み合わせて使うと
while(<>){
chomp;
s/\s+/ /;
print"<$_>\n";
}
となります。
このプログラムは置き換え結果を<>で囲んでプリントしてしまいます。
このプログラムを実行すると
1 2 3 ユーザー入力
<1 2 3>
1 2 3 ユーザー入力
< 1 2 3>
これは 一つ目は1と2の間に置き換えられていてスペースは一つ分になっています。
二つ目は1の前に置き換えられていて 1の前にスペースが一つ分入っています。
正規表現にマッチする部分全てを置き換えたいときは最後に g をつけます。
s/\s+/ /g;
となります。
while(<>){
chomp;
s/\s+/ /g;
print"<$_6gt\n";
}
実行すると
1 2 3 ユーザー入力
<1 2 3>
1 2 3 ユーザー入力
< 1 2 3>
となります。
置き換える文字列を計算することも出来ます。
例えば、
s/(\d+) (\d+)/$1+$2/e;
として
実行すると
10 20 ユーザー入力
<30>
となります。
これは オプションeをつけることによって
プログラムとして見なされ
$1+$2で 10+20を計算して答えを出して 計算結果に置き換えるものです。
*********************************************************************
************************************************************************************
17 さらに正規表現
**********************
大文字小文字を無視してマッチさせるには
そんなときは i オプションを使います。
例えば
/ab/i
にすると
"ab""Ab""aB""AB"
とマッチします。
*************************
単語の境界とマッチさせる
そんなときは /b オプションを使います。
book と言う正規表現は booksore handbook の両方ともにマッチしますが、
/bbook/b
にする事によって book という単語にだけマッチします。
**************************
繰り返しの回数を指定する
* は0回以上
+は一回以上の繰り返しでしたがもっとはっきりと指定する方法があります。
n には数を指定します。
{n} n回
{n,} n回以上
{n,m} n回以上、m回以下
となります。
例えば、
bo{2.4}nは
boon, booon, boooon
にマッチします。
回数を指定できる訳ね・・・
******************************
最長マッチと最短マッチ
次のプログラムではどうなるのでしょうか?
use English;
$str ="<12><34><56>";
if($str=~/<.*>/{
print"$match\n";
}
<,*> というのは<で始まり> で終わっていればその間はどんな文字でも構いません。
と言うことは次の6通りが考えられます。
<12><34><56>
<12><34>
<12>
<34><56>
<34>
<56>
となります。
さてどれがマッチするのでしょうか?
結局 <.*>は 可能な限り長い文字列とマッチしようとします。
だから 最も長い文字列でマッチするのは
<12><34><56>
となります。
最短マッチはどうなるのでしょう?
<.*?>にすると可能な限り短い文字列とマッチするようになります。
use English;
$str ="<12><34><56>";
if($str=~/<.*?>/{
print"$match\n";
}
こうすると
一番短くてこれも最初の方が優先されます。
だから
<12>
となるわけです。
**********************************
繰り返しマッチ
文字列の中ノ瀬行き表現にマッチする部分を全て調べたい場合があります。
そんなときはgオプションとwhileを使います。
use English;
$str="<12><34><56>";
while($str=~/<.*?>/g){
print"$match\n";
}
こうすると
<12>
<34>
<56>
となります。
**********************
最後の改行を取り除く
すでに出てきましたが最後の改行を取り除く関数は chomp です。
引き数なしの場合は、 $_の最後の改行を取り除きます。
引き数で変数を指定するとその変数の最後の改行を取り除きます。
****************************
文字列をつなぐ
文字列をつないで新しい文字列を作る演算子は .(ピリオド)です。
例えば
$b="Cloud";
$c-"Barett";
$t="Tifa";
$str=$b.$c.$t;
とすると$strには、$b,$c,$t,をつないだ "CloudBarettTifa"という
文字列が代入されます。
$str="$b$c$t";
としても同じです。
便利だねー
ピリオド演算子は
$a.=$b;
とすると
$a の後ろに $b を追加します。
「.=」は「+=」と同じです。
$a.=$b;は$a=$a.$b; と同じです。
**********************************
部分文字列を取り出す
文字列を取り出すためには substr を使います。
$substr($str,2,3)
となっていれば文字列の2つ目から3つ分を取り出すことを表します。
$substr($str,-8,3)
となっていれば文字列の最後から8個目から3つ分を取り出すことを表します。
$substr($str,2,-5)
となっていれば文字列の2つ目から最後の文字から5つ目迄を取り出すことを表します。
$substr($str,2)
となっていれば 文字列の2つ目から全部を取り出すことを表します。
1234567890
が文字列だとすれば
$substr($str,2,3) 345
$substr($str,-8,3) 345
$substr($str,2,-5) 345
$substr($str,2) 34567890
となります。
さらに substr は 代入もできます。
$str="0123456789"
substr($str,2,3)="*****";
print"$str\n";
とすると
$str の部分に*****が代入されます。
実行すると
全ての文字列の中から最初の2つ目から3つの文字列を取り出すのですから
234を取り出し、***** に代入します。
よって
01***56789
となります。
*******************************
文字の置き換え
ある文字を全部別の文字に置き換えると言うこともできます。
tr と言う 関数を使います。
置き換えもとの文字と置き換え先の文字を指定します。
「tr/元の文字/先の文字」と書きます。
$str="abcdefabcdef";
$str=~tr/acd/CEA/;
$print"$str\n";
$str=~tr/acd/CEA/;
は acd の文字列を全て CEA に置き換えると言う意味です。
実行すると
CbEdAfCbEdAf
となります。
***************************************
同じ文字列を繰り返した文字列を作る
文字列x回数
で 文字列を回数分だけ繰り返すことが出来ます。
x は エックスです。
例えば
$str="abc"x5;
となっていれば$strには
abcabcabcabcabc
が代入されます。
$str="abcx8";
となっていればabc は8回繰り返して代入されます。
**********************************************
************************************************************************************
18 配列
****************
今まで出てきた変数は全て $ がついていました。
この変数のことをスカラーと言いましたが、当然他にもあります。
@ は 配列を意味します。
% は 連想配列を意味します。
配列とはスカラー変数が一列に並んだものです。
配列の中の一つ一つの変数を「要素」と言います。
c言語を勉強していれば簡単なのですがみなさんは覚えていますか?
要素に値を入れたり、値を取り出したりするときには
「何番目?」と言う指定の仕方をします。
「2番目の値を下さい」とか1番目に"Aerith"をセットして」と言う風に使います。
詳しくすると
「2番目のスカラー変数に入っている値をちょうだい」とか
「1番目のスカラー変数に"Aerith"をセットして下さい」とかになります。
この「何番目?」と言うのを配列と言います。
perlの場合もcと同じように0から始まります。
perlの配列は先頭に@をつけます。
例えば
@party=("Cloud",Barett",Tifa");
となります。
これは
1番目に"Cloud"
2番目に"Barett"
3番目に"Tifa"
と言う値を セットするよと言う意味です。
配列の中のここの要素にアクセスする場合は$party[1]のように書きます。
$party[0]="Cloud";
$party[1]="Barett";
$party[2]="Tifa";
となります。
これは$party[0]番目の要素には"Cloud"が代入されてるよと言う意味になります。
配列も要素の一つなのでインデックスを指定するときには[]を使います。
まとめると
$party partyというスカラー変数
@party partyという配列全体
$party[1] partyという配列の1番目の要素(スカラー変数)
応用すると
$someone=$party[0]; 0番目の要素を取り出す。
$party[1]=$someone; 1番目の要素に代入
@left=@right; 配列全体の代入。@rightを読み出して@leftに代入
てな事になります。
c言語をやっていれば簡単なことです。
解らない人は c言語を基本から勉強した方がよいです。
****************************************************
************************************************************************************
19 ダブルクオートでの展開
***************************
配列変数をだぶるクオート文字列の中に書くと、全部の要素の値をスペースで区切って
並べた文字列に展開されます。
@party=("Cloud","Barett","Tifa");
print"party=@party\n";
実行すると
party=Cloud Barett Tifa
となります。
***********************
リスト
*********************
全体を括弧で囲んでカンマで区切って値を並べたものをリストと言います。
全体を囲む括弧は省略可能な場合もありますが、必ずつけるようにしましょう。
リストを代入分の右辺に書くと配列の値を作ることが出来ます。
例えばすでに出てきた例ですが、次の代入分の右辺がリストです。
@party=("Cloud","Barett","Tifa");
もちろん、リストに並べるのは変数でも式でも構いません。
$x=10;
@a=($x,$x+20);
を実行すると@a は 10と30の配列になります。
リストの中に配列変数を書くとその部分に配列変数の値が展開されます。
それは
@a=("a","b","c");
@b=(1,2,@a,3);
と書くと@b の値は
(1,2,"a","b","c",3);
となります。
これを応用すると
($x,$y,$z)=(1,2,3);
は
$x=1;
$y=2;
$z=3;
と同じになります。
($x,$y,$z)=@a;
は 右辺に配列変数を書いてありますが構いません。
これは
$x=$a[0];
$y=$a[1];
$z=$a[2];
となります。
**********************************
************************************************************************************
20 スカラーコンテキストとリストコンテキスト
********************************************+++
コンテキストとは文脈と言う意味があります。
perlには2つのコンテキストがあります。
1つの値を計算しようとしているスカラーコンテキストと
複数の値を計算しようとしているリストコンテキストです。
簡単に言うと
$x=右辺 は一つの値を計算しようとしているのでスカラーコンテキスト
@a=右辺 配列変数に代入しようとする場合は右辺はリストコンテキストになります。
括弧とカンマで作るリストの中もリストコンテキストです。
組み込み関数によっては、引き数がリストコンテキストになる場合があります。
よく使う関数の中ではprintの引き数がリストコンテキストです。
<> <stdin> は1行入力する演算子だと説明しました。
実は1行入力するのはスカラーコンテキストの場合です。
<>や <stdin>をリストコンテキストで使うと、入力を全部読み込んでその各行を要素にした
配列を返します。
@all<>
と書くと全入力が行の配列として@allに代入されます。
$str="1:23:45";
($hour,$min,$sec)=($str=~/(\d+):(\d+):(\d+)/);
を実行すると$hourに 1, $minに23 $secに45が代入されます。
gオプションをつけた場合には繰り返しパターンマッチをして、全てのマッチ($matchの値)
の配列を返します。例えば
$str="perl tcl java";
@allmatch=($str=~/(\w+)/g);
を実行すると @allmatchには "perl" "tcl" "java" の3つの要素の配列が代入されます。
むずかしー!!!
*************************************
************************************************************************************
21 要素
**************
要素の個数を調べるには
@a=(1,2,3);
$count=@a;
@b=@a;
2行目の$count=@a;
では@aがスカラーコンテキストで計算されて、$countには@aの長さ 3 が代入されます。
3行目の@b=@a; の方はリストコンテキストなので、普通の配列の代入になります。
最後の要素のインデックスを返すという特別な変数を使います。
各配列ごとに「$#配列名」と言う特別な変数があります。
例えば@aという配列なら$#aという変数です。
これが並列の最後の要素のインデックスになります。
これを利用すると$#a+1 が要素の個数になります。
$count=@party;
$count=$#party+1;
$#party+1 のよいところはコンテキストに依存しないところです。
$#配列名 と言う変数は読み出すだけでなく、書き込むことも出来ます。
$#配列名 に書き込むとその値が最後のインデックスになるように配列の長さが変わります。
例えば
@a=(1,2,3,4,5);
$#a=2;
を実行すると@aは(1,2,3)の3つの要素だけになります。
4,5は消えてしまいます。
****************************
配列の全要素について
配列の善要素について何かするというのは、良くある繰り返しのパターンです。
@partyの全要素をプリントしてみましょう。
for($i=0; $i<@party; $i++){
print"$i: $party[$i]\n";
}
次のように書いても構いません。
for($i=0; $i<=$#party; $i++){
print"$i: $party[$i]\n";
}
繰り返しの中でインデックスの値(上の例では$i)を使いたい場合は、このfor文を使います。
もう一つforeachという構文があります。
foreachは配列の全要素について指定した変数(下の例では$name)に要素を代入して
繰り返して実行してくれると言う構文です。
foreach $name(@party){
print"$name\n";
}
変数の指定を省略すると$_が使われます。
従って次と同じです。
foreach(@party){
print"$_\n";
}
foreachとforは同じ意味です。
for(@party){
print"$_\n";
}
でも全く一緒です。
インデックスを使う方はfor
使わない方はforeachにしてもよいです。
******************************************
************************************************************************************
22 配列操作
****************
配列はスカラー変数が一列に並んだものなので、一番前と一番後ろがあります。
配列の一番前から取り出すためにはshiftを使います。
配列の一番前に追加するにはunshiftを使います。
配列の一番後ろから要素を取り出すためにはpopを使います。
配列の一番後ろに追加するためにはpushを使います。
配列 @a があります。
$a[0]="a";
$a[1]="b";
$a[2]="c";
$a[3]="d";
$x=shift(@a);を実行すると
$a[0]="b";
$a[1]="c";
$a[2]="d";
となって"a"が取り出されます。
$x=pop(@a);を実行すると
$a[0]="a";
$a[1]="b";
$a[2]="c";
となって"d"が取り出されます。
反対にunshift(@a,1,2);を実行すると
$a[0]="1";
$a[1]="2";
$a[2]="a";
$a[3]="b";
$a[4]="c";
となって配列の前に1,2が追加されます。
同じようにpush(@1,2);を実行すると
$a[0]="a";
$a[1]="b";
$a[2]="c";
$a[3]="1";
$a[4]="2";
となります。
もっと複雑なこともできます。
ほとんど万能なコマンドそれは splice です。
spliceは配列の一部の要素を取り出してその部分に別の要素を入れます。
@party=("Cloud","Barett","Cid","Vincent");
@deleted=splice(@party,1,2,"Tifa","Yuffie","Aerith");
まず1行目の引き数 @party が操作する配列です。
1が取り出す部分の先頭の要素のインデックス
2が取り出す部分の長さです。
気をつけなくてはいけないのは
$party[0] "Cloud"
$party[1] "Barett"
$party[2] "Cid"
$party[3] "Vincent"
となるので $party[1] の"Barett"から二つ分だから
"Barett"と"Cid"になります。
そして その二つは@deleteに代入されます。
(@party,1,2,"Tifa","Yuffie","Aerith")の"Tifa","Yuffie","Aerith"の部分は
取り出された二つの値の部分に入れる要素です。
だから
$party[0] "Cloud"
$party[1] "Tifa"
$party[2] "Yuffie"
$party[3] "Aerith"
$party[4] "Vincent"
と 変化します。
文字列などを取り出してその取り出した部分に何かを入れるときはとても便利です。
******************************************
************************************************************************************
23 並べ替え
****************
配列の要素を順番に並べ替えた配列を返すsortという関数があります。
何も指定しないと、配列の要素を文字列と考えてアルファベット順に並べ替えます。
@party=("Sephiroth","Barett",Cloud");
@sorted=sort(@party);
を実行すると@sortedには
"Barett","Cloud","Sephiroth"の順に並んだ配列が代入されます。
そういうときは
@sorted=sort(@party);
とします。
結局、$aを$bより前にすると言うことです。
逆順にしたいときは
@sorted=reverse(sort(@party));
とします。
問題は数字の時です。
@nums=(2,30,100);
@sorted=sort(@nums);
これの答えは
100,2,30 になってしまいます。
数字の時は文字の先頭の文字だけをソートしてしまうからです。
こんな時は
@sorted=sort{$a<=>$b}@nums;
とします。
数として比較するときは <=>を使います。
**********************************************
************************************************************************************
24 連想配列
***************
連想配列も配列と同じように複数の志カラー変数の集まりです。
配列はスカラー変数が一列に並んでいましたが、
連想配列はバラバラです。
バラバラなので配列の様に何番目というアクセスは出来ません。
その代わりにそれぞれのスカラー変数に名前が付いているのです。
この名札を「キー」を言います。
連想配列では何番目の代わりにキーを使って要素を指定するわけです。
%hp=("Cloud"=>500,"Barett"=>450,"Tifa"=>360);
と言う記述の中には
"Cloud"の中には 500という値が入っているよ と言う意味になります。
後はそれぞれ同じように解釈すればよいです。
=> は カンマ , と同じ意味です。
連想配列には順番は無いので
"Cloud"=>500 でも
500=>"Cloud" でも どっちでも構いません。
連想配列の 各要素をアクセスするためには中括弧 {} で キーを指定します。
$x=$hp{"Cloud"};
$hp{"Cloud"}=$x+100;
と言う感じです。
1行目は%hpという連想配列の中から"Cloud"というキーとついている変数の値を読み出して
$xに代入します。
$hp{"Cloud"}のように先頭に$ がつく理由は配列の場合と同じです。
連想配列の中のかく変数はスカラー変数だからです。
2行目は %hpの中の"Cloud"というキーの変数に値を代入します。
この2行は次の様に書くことが出来ます。
$hp{"Cloud"}+=100;
ある要素を削除するためにはdeleteを使います。
%hp=("Cloud"=>500,"Barett"=>450,"Tifa"=>360);
delete($hp{"Barett"});
を実行すると%hpから$hp{"Barett"}の要素が無くなります。
*****************************************************
************************************************************************************
25 例題
**************
単語の出現頻度
単語の出現頻度を調べてみましょう。
単語は単純に/w+ と言うパターンにします。
while(<>)で各行ごとにループして、その中で各単語ごとにループします。
全体は・・・
use English;
while(<>){
while(/\w+/g){
$word=$match;
各単語の処理
}
}
各単語の処理ですが、%Count と言う連想配列に出現回数を入れることにします。
単語がキーで値が回数です。
if(exists($Count{$word})){
$Count{$word}++;
}else{
$Count{$word}=1;
}
と言う感じになります。
すでに出現していたら一回増やして初めてだったら1にするというわけです。
ところで存在しないキーで読み出すと、undef(未定義)と言う値が帰ってきます。
undefは数としては0として扱われます。
と言うことは$Count{$word}++;でちゃんと1になるはずです。
結局if 文は無くても大丈夫と言うことになります。
プリント文を書き加えると
use English;
while(<>){
while(/\w+/g){
$word=$match;
$Count{$word}++;
}
}
foreach $key(sort(keys(%Count))){
print"$key\t$Count{$key}\n"
}
そして ソートします。
use English;
while(<>){
while(/\w+/g){
$word=$match;
$Count{$word}++;
}
}
foreach $key(sort{$Count{$b}<=>$Count{$a}}keys(%Count)){
print"$key\t$Count{$key}/n"
}
これで 出現頻度の高い順番にソートされます。
***********************************************
集合として
*********
連想配列はキーの集合として考えると良いです。
"a","b","c" と言う要素があります。
その連想配列は
%Set=("a"=>1,"b"=>1"c"=>1);
となります。
この集合に要素 "d"を追加するには
$Set{"d"}=1; を書き加えるだけで良いです。
要素"a"を削除するのは
delete($Set{"a"});
です。
ある要素 $x がその集合に含まれるかどうか調べるのは existsです。
if(exists($Set{$x})){
}
全ての要素の値を足すときは
%Set1=("a"=>1,"b"=>1,"c"=>1);
%Set2=("b"=>1,"c"=>1,"d"=>1);
%Union=(%Set1,%Set2);
これで それぞれの 値はUnionに代入されて和集合が出来ます。
積集合の法は片方の集合の要素(キー)に関してループを回してその要素がもう一方の集合にも
含まれていたら積集合に追加していきます。
%Intersection=();
foreach $key(keys(%Set1)){
if(exists($Set2{$key})){
$Intersection{$key}=1;
}
}
*************************************************
************************************************************************************
26 制御構造と関数
********************
制御構造
while
perlのwhileはC言語のwhile文よりも高機能です。
まずその一つは
continueブロックをつけることが出来ることです。
continueプロックとは本隊のプログラムが終わった後で実行されます。
for($i=0; $i<10; $i++){
print"$i\n";
}
と言うfor文をcontinueブロックを使うと
$i=0;
while($<10){
print"$i\n";
}continue}
$i++;
}
となります。
二つ目は
next
redo
last
です。
nextは C言語で言うとcontinue
lastはbreakに相当します。
redoはないのですが 結局はその条件のプログラムの先頭に戻ることを表します。
3つ目の機能として
ラベル があります。
ラベルは ループにラベルを付けておいて ジャンプするスタート地点にラベル名を記述します。
そうすると一気にジャンプするという機能です。
Toplevel:
while(1){
while(1){
while(1){
print"deep indide\n";
last Toplevel;
}
}
}
print"Toplevel\n";
となります。
一番最初のToplevel:の最後のコロンに気をつけて下さい。
セミコロンではありません。
逆にwhileの条件を逆にしたuntilもあります。
条件が逆なだけで whileと同じです。
*********************************************
関数
*************
関数を呼び出すときに括弧の中に書いた引き数は全て一つの配列 @_に入った状態で関数に
渡されます。
2つの配列@xと@yを引き数に入れて次のように関数を呼び出したとします。
@x=(1,2,3);
@y=(4,5,6);
sonmefunc(@x,@y);
関数の方では渡された2つの配列を2つのローカルな配列変数@a,@bに入れようと思って次のように
書きます。
sub somefunc{
my(@a,@b)=@_;
省略*****
}
結局 @_の値は(1,2,3,4,5,6) になります。
でも @_の値は@aには全て入りますが@bには何も入りません。
@a (1,2,3,4,5,6)
@b から
となります。
***************************************
************************************************************************************
27 UNIXの機能
*****************
ユニックスでのファイルオープン
open(F,"/etc/passwd");
openにはファイルハンドルとファイルのパス名を指定します。
Fがファイルハンドル"etc/passwd"がファイルのパスです。
openのパス名には先頭に記号をつけて入力なのか出力なのかを指定します。
例えば、
open(F,"<file")
の様にします。
読み込み "read"の"r"
書き込み "wright"の"w"
実行 "excute"の"e"
となります。
このモードは
open(F,r+<file")
open(F,w+<file")
となります。
ファイルオープンを失敗したら・・・
なんて事を試すのに使われるプログラムは
open(F,"$filename")or die("can't open: $filename\n");
です。
*********************
入力
ファイルから入力する場合はファイルから1行ずつ入力してそれをプリントする
プログラムを書きます。
$filename=/etc/passwd";
open(IN,"$filename")or die("can't open: $filename\n");
while(<IN>){
print;
}
close(IN);
ファイルハンドルを不等号で囲んで、<F>とすると、そのファイルハンドルから
1行入力します。
whileの条件の部分に<F>だけを書くと自動的に$_に代入されるのでそれをprintします。
***********************
出力
ファイルに出力するには、printやprintfでファイルハンドルを指定します。
例えば0から9までをファイルに書き出すプログラムは 次のようになります。
$filename="count";
open(OUT,">$filename")or die("can't open: $filename\n");
print($i=0; $i<10; $i++){
print OUT "$i\n";
}
openでファイルのパス名の前に「>」をつけて書き込み用としてオープンします。
そしてprint でファイルハンドルOUTを指定します。
OUTの後ろにはカンマをつけないことに注意して下さい。
*************************
クローズ
最後はクローズです。
クローズを書かなくともプログラムが終了するときに自動的にクローズしたりもしますが、
まあ、開けたものはしめるのが作法というものです。
**************************
ファイルの属性を調べる
$filenameが読めるかどうかを調べるには
if(-r $filename){
print"$filename is readable.\n";
}
となります。
-r や
-w や
-e などのように指定します。
そのほかに
chmod ファイルのモード(パーミッション)を変更する
chown ファイルの所有者、グループを変更する。
utime ファイルの最後にアクセスした時刻、最後に修正した時刻を変更する。
ファイル操作として
rename ファイル名を変更する
unlink ファイルを消す
link リンクする
symlink シンボリックリンクを作る
truncateファイルを指定した大きさに切りつめる
****************************************
インターネットスタートページ 鈴木維一郎 石橋三重子
|
|
|
|
|
|