情報システム科






Perl言語

Perl言語 の一部を紹介します。

目次

Perl言語の開発環境
Perl言語の文法   文字列と変数  演算子  正規表現  制御  関数  ファイル  リファレンス  文字コード  サブルーチンとライブラリ 
オブジェクト指向  継承
unixを使ってPerl言語


ディレクトリ内及びその下のディレクトリ内のファイルの内容を一気に、複数内容の置換え
ディレクトリ内のファイルの内容を一気に、複数内容の置換え
ファイル名の変更。ディレクトリ内及びその下のディレクトリ内のファイル名
ファイル名の変更。そのディレクトリ内のファイル名
ファイルの内容を表示  配列  コマンドライン引数  正規表現  行番号を付ける  行番号を削除  再帰を使って階乗を計算する  再帰を使ってフィボナッチ関数を計算する  ハノイの塔 

Perl言語の開発環境

学校では、パソコンに既にインストールしてありましたが、自宅で個人的に勉強するときは、 検索エンジンで探して、条件や注意をよく読んで、同意できる場合、ダウンロードします。

参考
「Perlを始めよう」
AOK's Home Page (Vector)
Perl
ActivePerl | download---ActivePerl 5.6.1 build 635 Windows MSI 8.6MB


WindowsをUNIX風に Cygwin
UNIX風のエディタ Emacs

一口メモ
 文法チェックのコマンド
   perl -c easydb.pl
 DOS出力をページ毎に出力
   perl easydb.pl | more
 > は >
 < は &lt;

Perl言語の文法

文字列と変数

文字列
文字列には、両端をシングルクォート(')で囲むシングルクォート文字列とダブルクォート(")で囲むダブルクォート文字列があります。いずれも文字列を表現するのに使えますが、次のような違いがあります。
シングルクォートでは、 \ と ' を表現するのに,それぞれ \\ と \' と記述する。
ダブルクォートでは、バックスラッシュエスケープと呼ばれるあらかじめ予約された文字列を利用できる。例えば、
\n - 改行
\t - tab
\" - ダブルクォート

次はそれぞれの文字列の例です。
シングルクォート ダブルクォート 表現したい文字列 
'hello'          "hello"          hello 
'Don\'t do it!'  "Don't do it!"   Don't do it! 
'hello           "hello           hello(改行) 
there'            there"          there 
                 "hello\nthere"   hello(改行) 
                                  there 
$name="tokyo";
print "this is $name\n"; # this is tokyo と表示(変数展開をする)
print 'this is $name';   # this is $name と表示
$   変数  例 $a
[]  配列 例 $ab[0]
{}  ハッシュ $ab{"tokyo"}
@   配列全体 例 @ab
%   ハッシュ全体 例 %a=("tokyo","03","oosaka","06");
                      %a=("tokyo" => "03", "oosaka" => "06");
          $a{"tokyo"} は "03" を示す
          $r=\%a ; $r->{"tokyo"}は"03"を示す。$rはリファレンス
=>        $r={"to"=>"03","oo"=>"06"}; $r->{"to"}は"03"を示す。$rはリファレンス
@ISA 継承のスーパークラスを定義 例 @ISA (Class2);
$_  あれ foreachの変数を省略すると $_ に入る
$.  現在の行番号
$! errno の現在値またはシステムエラー文字列 
()  リスト  例 @ab=(123.5,234.5,45.7);
()=() 変数の交換 例 ($a,$b)=($b,$a);
[-1]  配列の最後の要素  例 $a[-1]    $a[-2] 最後から2番目
[0,1] スライス  例 @a[0,1,2] は ($a[0],$a[1],$a[2]) と同じ
[0..3]      例 @a[0..2]  は ($a[0],$a[1],$a[2]) と同じ
0..3              例 @a=0..2;   で $aには(0,1,2)が入る
undef  未定義の値
    初期化されていない変数
     ・数値としてみた場合は  0
     ・文字列としてみた場合は ""
<<    ヒアドキュメント(here document) 
    print <<エンドトークン 文; 文; エンドトークン(end token)
            例 print <<EOD "$a\n"; "$b\n"; EOD



コンテキスト ーーリストコンテキスト  と  スカラーコンテキスト
  リストコンテキスト(配列全体を表し、値はリストになる)
    リストに代入する時  例 ($cd,$ef,$gh)=@ab;
    リストを代入する時  例 @ab=(123.5,234.5,45.7);
    配列同士を代入する時 例 @ab=@sa;
  スカラーコンテキスト(配列の要素数という1つの数値になる)
    スカラー変数に代入する時 例 $su=@ab;
    数値と比較する時     例 @ab > 0;
    数式の一部として使う時  例 @ab+1
+=  演算 例 $a += 10;  内容 $a = $a +10;
           -=   *=   /=   **= (乗)  %= (余り)
++  インクリメント 例 ++$a;  内容 $a = $a +1;
                     --
.   文字列の結合 例 $a = $b." ".$c;  内容 1スペース空けて結合
                   例 $a .= ",";       内容 末尾に,をつける
<   比較演算子
        >  <=  >=  ==  !=
eq  文字列として比較 例 if($a eq $b)
    文字列の比較演算子
        lt  less than  ($x lt "a")    $xが"a"より小さい 
        gt  greater than 
        le  les than or equal  ($x le "a")  $xが"a"以下
        ge  greater then or eqal
        eq  equal
        ne  not equal

演算子


//  マッチ演算子(m//) 例 if(/love/)  $_が文字列の一部に一致すれば真
s///置換演算子(substitute)
    s/置換え前の文字列/置換え後の文字列/  対象はあれ($_)
    例 s/abc/efg/ 文字列の置換 abc→efg
    例 s/abc//     文字列の削除
tr/// 1文字単位の置換(translitarate)
        例 tr/ab/xy/    a→x b→y に置換わる
        例 tr/a-z/A-Z/  小文字が大文字に変わる
        例 tr/a-z/A-G/ aからgがAからGに変わり、hからzがGに変わる
    例 $i=tr/a/a/;  $_内のaの個数
=~  変数の中身をマッチ
    例 $a=~ tr/a-z/A-Z/;
g   マッチするすべてを置換(global)
    例 s/abc/efg/g
i   大文字小文字を無視する 例 s/ab/cd/ig すべての大文字と小文字
?   最小マッチ  
    デフォルトでは二通り以上の解釈がある場合は長いほうをとる
    マッチ演算子の繰り返しに ? をつけると最小マッチに
    例 /<.*?>//g  タグを削除する
?   条件演算子 
   例 $A==0 ? expr1 : expr2
     $A==0 が成立すれば expr1 を実行し、そうでなければ expr2を実行 
()  ()で囲んだ部分だけを抽出
    例 /<(.*?)>/g
  ()で囲んだ部分を記憶し、$1,$2・・・という変数に順番に入る
    例 s/(\S+) (\S+)/$2 $1/; 名前と苗字の入れ替え
$`  マッチするまでの文字列
$& マッチした文字列
$' マッチした後の文字列
<>  ダイヤモンド演算子
    入力リダイレクションを渡されたときは入力から <STDIN>
    ファイル名を渡されたときはファイルから
    ファイル名のリストを渡されたときは、連続してレコードを読み込む
-f  ファイルチェック演算子。 ファイル名なら真 例 if(-f $file)
-d  ファイルチェック演算子。 ディレクトリなら真
-T  ファイルチェック演算子。 テキストファイルなら真
-B  ファイルチェック演算子。 バイナリーなら真

x   文字列を複数回繰り返す x 演算子。例 $b='ab'x3; $bはababab



正規表現

正規表現
$   文字列の末尾にマッチ 例 /love$/     love で終わる文字列
^   文字列の先頭にマッチ
・・文字クラス
[abc] aかbかcのどれか    例 /[abc]/  どれかにマッチ
[a-z] 任意の小文字
[^a-z]文字クラスの否定−−動かない−−
\d  数字(digit)           [0-9]と同じ
\D  数字以外          −−動かない−−
\w  英数字(word)
\W  英数字以外        −−動かない−−
\s  スペース          −−動かない−−
\S  スペース以外 
\b  単語境界(word boundary) 英数字と空白または文字列の端との間
    /abc/だと"abcd"にもマッチするが
    /\babc\d/だと"abc"にしかマッチしない
.   任意の一文字

繰り返し
*   0回以上の繰り返し
+   1回以上の繰り返し
?   0回か1回 例 a?
{}  繰り返し  例  a{5} 5回繰り返し aaaaa と同じ
{,} 繰り返し  例 a{3,} 3回以上繰り返し aaa+ と同じ
        例 a{3,5} 3回以上5回以下繰り返し

グループと選択
()  グループ化 例 ab(cd)+  は abcd  abcdcd  abcdcdcd
|   どれかにマッチ 例 stud(y|ies) は study studies

位置指定
^   先頭  例 ^a
$   末尾  例  a$

エスケープ
\   特殊記号自身を表す時 例 \^ は ^ にマッチ
    特種記号以外では書かないのと同じ
\Q \E \Qと\Eの間は、全部\が挿入されるのと同じ
    例 /\Qo)^+\E/ は o)^+ と言う文字列にマッチ

スイッチ
c   search-list で指定した文字以外の文字をreplace-listの1 文字に置き換え
      例  $_ = 'abcABCdefDEFghi';
          tr/a-z/A/c;      # $_ => 'abcAAAdefAAAghi'
          tr/a-z/A/cs;     # $_ => 'abcAdefAghi'
d   search-list にあって、replace-list に対応する置き換え文字が指定されていない文字を削除
      例 $_ = 'abcABCdefDEFghi';
         tr/a-z//d;       # $_ => 'ABCDEF'
         tr/a-z/ABC/d;    # $_ => 'ABCABCDEF'
e   置換部分を Perl の式として評価し、その結果を置換文字列とする
      例 $_ = "ab1234ef";s/\d+/$&*2/e; $_は"ab2468ef"
          マッチした1234の*2の2468に置き換わる
g   pattern と一致する部分を全て置換  例 s/abc/123/g;
i   大文字小文字を無視する 例 /ab/i
o   1 回だけコンパイル      例  s/abc/123/o
s   変換後に同じ文字が続いた場合、1 文字に圧縮
      例 $_ = 'abcdABCDefghEFGH' とすると
         tr/a-z/a/;     # $_ => aaaaABCDaaaaEFGH
         tr/a-z/a/s;    # $_ => aABCDaEFGH






区切り文字を変える
m   m(match)の直後の記号が区切り文字になる 例 m#///# は /\/\/\//と同じ

後方参照
カッコ () はその中の正規表現と一致した文字列を覚えていて、後からそれを
使うことができる。
「\ + 数字」でカッコと一致した文字列を参照することができる。一番左側に
ある ( )が \1 に対応し、次の ( )が \2に対応。
例 /(\w+)\s+\1/ は abc abc にマッチ。
カッコで記憶した文字列は、正規表現の外でも使うことができる。この場合、
特殊変数 $1, $2, $3, ... で取り出す。




制御


if    if(条件){命令;
      }elseif(){命令;
      }else{命令;
      }
unless(条件){命令}  条件が偽なら・・・

while 条件が満たされている間実行
      while(条件){
        命令;
      }
for   for(最初に実行;判定;最後に実行){
        命令;
      }
foreach  配列要素を1個ずつ全部処理する
   foreach $cd (@ab){
          $sum += $cd;
      }
   配列@abの要素を全部たすプログラムです
redo; ループの先頭に戻る
last; ループを脱出
die   引数のメッセージを出力してプログラムが死ぬ
     例 unless(@ab){die "リストが0です"}
or    真だったら次を飛ばして先に行く
     例 ($a==3) or die "3以外は使えません";
and   真だったら次に行く
条件 0と""が偽

式2 if 式1;        # 式1が成り立てば式2を実行
式2 unless 式1;    # 式1が不成立であれば式2を実行
式2 while 式1;     # 式1が成立している間、式2を実行
式2 until 式1;     # 式1が不成立の間、式2を実行



関数

print 以下は同じものを出力
        print "2003 new year\n";
        print "2003 "."new "."year"."\n";
        print ("2003 "."new "."year"."\n");
        $a=2003; print $a." new year\n";
        $a=2003; print "$a new year\n";

@ARGV 引数を入れる ARGument Value
eval  文字列をPerlプログラムとして解釈
     例 $a="print 2+3";
              eval($a);
chomp;  $_の右端の改行コードを切り落とす chomp(変数); 変数をchomp
substr  部分文字列 substr(対象文字列,開始位置,長さ)
      例 substr($a,1,3);  開始位置は0から
length  文字列の長さ length(文字列) 例 length($a);
split   文字列を分割
     split(/区切り文字のパターン/,区切る対象,区切る上限個数);
     split(/区切り文字のパターン/,区切る対象); #すべて
     split(/区切り文字のパターン/);            #あれ($_)を区切る
     split;                           #空白文字、タブで区切る
      例 @a=split(/,/);
                $_="123 456 789";@b=split;# @b => ("123", "456", "789")
join    文字列をつなぐ
          join(間に挟む文字列,つなぐ文字列のリスト);
      例 print join(",",split)."\n"; タブ区切り→カンマ区切り
glob    フィル名を返す 例 $a=glob("*.txt");
system  OSのコマンドを呼び出す 例 system("dir");
sort    ソート  例 @a=sort(glob("*"));
qw      文字列のリストを作る(quote words)
           例 @a=qw(ab cd e); は @a=("ab","cd","e"); と同じ
each    ハッシュから順にデータを取り出す。取り出す順序は順不同
      例 each(%a);     while(($key,$value)=each(%ENV)){・・・}
keys    ハッシュのキーの一覧
           例 foreach $a (sort(keys(%ENV))){ 
values  ハッシュの値の一覧を返す 例 values(%a)
delete  ハッシュの要素を削除   例 delete $b{tokyo};
rand    乱数を発生 例 srand;$r=int(rand(9)); # 0から9を発生
srand   乱数シードを設定。引数が省略されると、time の値。

use English;   特種変数を名前で
$ARG                        $_  あれ
$INPUT_LINE_NUMBERまたは$NR $.  現在入力中の行番号
$PREMATCH                   $`  マッチ前
$MATCH           $&  マッチ
$POSTMATCH         $'  マッチ後
$PROGRAM_NAME        $0  現在実行中のプログラム名

&関数(もしあれば引数のりスト); 関数の呼び出し &は省略できる
      例  &func(2,3);
sub 関数
      sub 関数名{
        my(引数が入る変数のリスト)=@_;
        ・・・・・・・
        return(戻り値);
      }
      returnがない場合、戻り値はブロックの最後で実行された処理結果。
      例  sub func{print "[@_]\n";}
my  ローカル変数
@_  引数のリストが入る配列 $_[0]で0番目の引数
push       配列の最後尾にデータを追加する
pop        配列の最後尾からデータを取り出す
shift      配列の先頭からデータを取り出す
unshift    配列の先頭にデータを追加する
pop と shift は、引数が省略されると @ARGV を操作


ファイル


open  ファイルのオープン open(ファイルハンドル名,"ファイル名");
   ファイルの入力   open(IN1,"abc.txt");
   入力        <IN1>
   ファイルへの出力  open(OUT1,">abc.txt");
   ファイルへの追加書 open(OUT1,">>abc.txt");
   出力        print OUT1 $a;
close ファイルのクローズ close(OUT1);
select 出力ファイルハンドルを変える
          select (OUT1);   この後print はOUT1 へ出力
     select (STDOUT); STDOUT に戻す
read  文字数を指定してファイルを読み込む
     read(ファイルハンドル,読み込む変数,読み込みたい長さ)
      例 while(read(IN1,$c,1)){

リファレンス

C言語のポインタと同じようなもの
Perl のリファレンスは、C言語のポインタと同じく、あるメモリ領域を指し 示す。C言語の場合、メモリ領域のアドレスをそのまま使いますが、 Perl ではリファレンスを、数値や文字列と同じスカラー型データとして扱う。
C言語のポインタと違って、アドレスを操作することはできない。
$a=20;
$r=\$a;                # 変数の前に \ をつけて、リファレンスを代入
print "\$a-->$a\n";
print "\$r-->$r\n";
print "\$\$r-->$$r\n"; # $をつけて、デリファレンス $$r
$$r=1000;              # $$rにも、代入できる
print "\$\$r-->$$r\n"; 
print "\$a-->$a\n";
実行結果
$a-->20
$r-->SCALAR(0x1832834)
$$r-->20
$$r-->1000
$a-->1000


配列のリファレンス
@a = (10, 20, 30, 40);
$ra = \@a;          # $ra は @a へのリファレンス
print @$ra."\n";         # 配列全体を表示(配列の個数 4 を表示)
print $$ra[0]."\n";      # 0 番目の要素 10 を表示
print $ra->[1]."\n";     # 矢印演算子 (1 番目の要素 20 を表示)
print ${$ra}[2]."\n";    # ブロック {} を使う(2 番目の要素 30 を表示)
print ${$ra[3]}."\n";    # 何も表示されない


配列にリファレンスを格納
@ra = \(10, 20, 30, 40); # 各要素のリファレンスを格納するリストを生成
print ${$ra[3]}."\n";    # 3 番目の要素をデリファレンス (40 を表示)

ハッシュへのリファレンス
%h = ("abc"=>10, "def"=>20, "ghi"=>30, "op"=>40);
$rh = \%h;                  # リファレンス
print %h."\n";              # 4/8 と表示
print $rh."\n";             # HASH(0x1832884) と表示
print %$rh."\n";            # 4/8 と表示。ハッシュ全体を表示
print $rh->{"abc"}."\n\n";  # 10 と表示。$$rh{"abc"} と同じ
$r = {"abc"=>10, "def"=>20, "ghi"=>30, "op"=>40};
print $r."\n";              # 4HASH(0x183f14c) と表示。$rはリファレンス
print $$r{"abc"}."\n";      # 10 と表示
print $r->{"abc"}."\n";     # 10 と表示

文字コード

ASCII

MSB(Most Significant Bit)が常に0の8ビットコード

JISコード

文字の種類が切り替わるごとに、3バイトのESCシーケンス(シフトコード)が入る。
 ・新JIS漢字の始まり・・・Esc$B<br>  ・半角カナの始まり・・・・・Esc(I<br>  ・ASCIIの始まり・・・・Esc(B<br>  ・JISローマ字の始まり・・Esc(J<br>  ・旧JIS漢字の始まり・・・Esc$@<br>  ・補助漢字・・・・・・・・・Esc$D<br>

シフトJISコード(Microsoft)(MS漢字コード)

 ・英数字はASCII<br>  ・半角カナは8ビットモードのJIS半角カナ<br>  ・漢字は1バイト目のMSBが必ず1<br>  ・シフトコードは使わない<br>

EUC(UNIX)

Unicode(Windows NT)(Java)

世界中を1つのコードで

漢字コードを表示しよう


while(read(STDIN,$c,1)){
	print unpack("H2",$c); #H2は2桁の16進数
	print "\n";
}

サブルーチンとライブラリ

サブルーチンの例(値渡し)
print &add(3, 5);  #サブルーチンを呼び出す
#サブルーチンの宣言
sub add {
    return($_[0] + $_[1]);
}

型グロブによる方法(c言語のポインタのよう)
$a = 100 ;
&add_10 ( *a );     # 型グロブの渡し
print $a ;          # 表示  →  110
sub add_10{
    local *b = $_[0] ;  # 引数の取得
    $b = 10+$b ;        # 変数の更新
}

リファレンスによる方法
$a = 100 ;
&add_10 ( \$a ) ;   # リファレンス渡し
print $a ;          # 表示  →  110
sub add_10 {
    my $b = $_[0] ;   # 参照渡しの受け取り
    $$b = 10 + $$b;   # デリファレンスして代入($aへの代入と同じ)
}  



ライブラリの作成

ライブラリの作成例(calc.pl)
package calc;   #ライブラリで用いる名前空間名
sub add {
    return($_[0] + $_[1]);
}
1;
ライブラリーの利用例
require "calc.pl";      #ライブラリの使用を宣言する(必須)
print &calc'add(3, 5);  #パッケージ内のサブルーチンや変数は、「パッケージ名'名前」で指定

ライブラリは Perl4 の時に使用されていた方法でPerl5からは《 オブジェクト指向 》をサポートしておりモジュール(.pm )が使用される。



オブジェクト指向

オブジェクト−−−「物」の概念をモデル化。「物」の状態と振る舞い。
クラス(class)−−−設計図。
インスタンス−−−クラスは設計図であり、それに従って作られるオブジェクト
メソッド(method)−−オブジェクトの振る舞いをサブルーチンで表現。第1引数が必ずオブジェクトへのリファレンスとなる。

クラスの宣言−−−package 文を使ってクラスを宣言。package クラス名;
   例 package Class; # クラス名 Class を作成
コンストラクタの作成−−−新しいオブジェクトを作成し、そのリファレンスを返すメソッド。
  new という名前でメソッドを定義する
  第1引数のクラス名を受け取る
  bless 関数でオブジェクトのリファレンスを返す
bless 関数−−−第1引数で与えられたリファレンスが指すオブジェクトは、第2引数で指定したクラスに所属するよう定義。
インスタンス変数−−−bless した変数はクラスのオブジェクトに属することになるので、普通の変数と区別するためにインスタンス変数と呼ばれる。

メソッドの作成−−−サブルーチンとほぼ同じ。ただし、第1引数にオブジェクトへのリファレンスが渡される。

クラスの利用−−−モジュールのようにメソッドを直接呼び出したりするよりは、クラスから返されるオブジェクトリファレンスを通して呼び出す。
  クラスを外部から呼び出すとき
  use Class; # クラス名 Class をインポート
  my $obj = new Class; # クラスのオブジェクトリファレンスを作成
  $obj->method1(); # メソッド method1 の呼び出し
  $x = $obj->{X}; # インスタンス変数の呼び出し
  但し、普通は、アクセスメソッドからインスタンス変数にアクセスする

デストラクタ−−−オブジェクトの削除。
 クラスに DESTROY メソッドが定義されていると、そのクラスに属する bless されたオブジェクトが破棄される直前に、自動的に DESTROY が呼び出される。
package Point;  # クラス名 Point を作成
sub new {       # コンストラクタの作成(インスタンスを生成するメソッド)
    my $class = shift;  # 第1引数のクラス名を受け取る
    my ($x,$y) = @_;
    my $obj={"x"=>$x,"y"=>$y};# オブジェクト。ハッシュのリファレンスを作成
    bless $obj, $class;       # bless 関数。
    return $obj;              # オブジェクトのリファレンスを返す
}

sub distance {   #  メソッドの作成(2点間の距離を計算)
  my ($obj1, $obj2) = @_;
  my $dx=$obj1->{"x"}-$obj2->{"x"};
  my $dy=$obj1->{'y'}-$obj2->{'y'};
  sqrt( $dx * $dx + $dy * $dy );
}

package main;
$obj = new Point(10,20); # クラスのオブジェクトリファレンスを作成
print $obj->{"x"}."\t".$obj->{"y"}."\n"; # 10   20 と表示
$p1 = new Point(0,0);
$p2 = Point->new( 10, 10 );
$len1 = $p1->distance( $p2 );
$len2 = distance $p1( $p2 );
print "$len1  $len2\n"; # 14.142135623731  14.142135623731と表示


継承

一般のオブジェクト指向言語では、属性と実装が継承されるが、Perl は実装は継承されるが、属性は継承されない。つまり、Perl では継承されるのはメソッドだけ。
package A;
sub new {      # インスタンスの生成
  my ($type,$a,$b) = @_;
  my $obj = {'a'=>$a,'b'=>$b };
  bless $obj, $type;
  $obj;
}
sub get_a {    # アクセスメソッド
  my $obj = shift;
  $obj->{'a'};
}
sub get_b {    # アクセスメソッド
  my $obj = shift;
  $obj->{'b'};
}
package B;
@ISA = (A);    # A を継承
sub new {      # インスタンスの生成
  my ($type, $a, $b, $c) = @_;
  my $obj = $type->SUPER::new($a,$b);
  $obj->{'c'} = $c;
  $obj;
}
sub get_c {    # アクセスメソッド
  my $obj = shift;
  return $obj->{'c'};
}

$o1 = A->new( 1 ,2);
$o2 = B->new( 10, 20 ,30);
print $o1->get_a(), "\n";    #  1 を出力
print $o2->get_a(), "\n";    # 10 を出力
print $o2->get_c(), "\n";    # 30 を出力




unixを使ってPerl言語

バージョンの確認
$ perl -v
This is perl, v5.6.1 built for ***

prelコマンドはそのまま打ち込むと、標準入力からの入力待ちとなる
$ perl
print ("hello\n");
hello
[Ctrl]+d
$

ファイルの内容を表示

# cat.pl
while(<>){ print; }
>perl cat.pl test.txt test2.txt
test.txtを表示
test2.txtを表示


行番号を表示
# cat.pl
while(<>){ print "$.: $_"; }
>perl cat.pl test.txt test2.txt
1: test.txtを表示
2: test2.txtを表示


標準入出力 con を使う
>copy con test3.txt
abc
test3.txt を上書きしますか? (Yes/No/All): y
abc
erg
^Z
        1 個のファイルをコピーしました。

>copy test3.txt con
abc
abc
erg
        1 個のファイルをコピーしました。

リダイレクト > を使う
>dir > test3.txt

>copy test3.txt con
 ドライブ C のボリューム ラベルは *** です
 ボリューム シリアル番号は *** です

 C:\test のディレクトリ

2003/03/05  11:34              .
2003/03/05  11:34              ..
2003/03/05  11:21                40 cat.pl
2003/03/05  11:24               371 cat.pl.html
2003/03/05  11:22                16 test.txt
2003/03/05  11:22                17 test2.txt
2003/03/05  11:40                 0 test3.txt
               5 個のファイル                 444 バイト
               2 個のディレクトリ  *** バイトの空き領域
        1 個のファイルをコピーしました。

配列

@a=0..4;
print "@a\n";  # 0 1 2 3 4 と表示
($c,$d,@e)=@a;
print "$c\n";  # 0 と表示
print "@e\n";  # 2 3 4 と表示
@f=@a[0,1,4];
print "@f\n";  # 0 1 4 と表示
@g=@a[1..3];
print "@g\n";  # 1 2 3 と表示

$h=@a;
print "$h\n";  # 5 と表示(スカラーに変換し、要素数となる)

# foreach
$sum = 0;
foreach $i (@a){
   $sum += $i;
}
print "$sum\n"; # 10 と表示(0 1 2 3 4 の合計)

open(IN, "test.txt");
@data = <IN>;    # test.txt の内容をすべて@dataに読み込む
close(IN);
print "@data\n"; # test.txt の内容を表示


push,pop,shift,unshift の例
@array = ();
for( $i = 0; $i < 2; $i++ ){
   push( @array, $i );    # 最後尾にデータを追加
   print "[@array]\n";
}
while( @array ){
   $i = pop( @array );    # 最後尾からデータを取り出す
   print "$i [@array]\n";
}
for( $i = 0; $i < 2; $i++ ){
   unshift( @array, $i ); # 先頭にデータを追加
   print "[@array]\n";
}
while( @array ){
   $i = shift( @array );  # 先頭からデータを取り出す
   print "$i [@array]\n";
}
動作結果
[0]
[0 1]
1 [0]
0 []
[0]
[1 0]
1 [0]
0 []


コマンドライン引数

# test.pl
print "$0\n";
print "[@ARGV]\n";
>perl test.pl abc ef hij
test.pl---------$0 の内容
[abc ef hij]----@ARCV の内容

正規表現

aかbかcのどれかだと、ok
while(<>){
    if (/[abc]/){print "ok\n";} # aかbかcのどれか
    else        {print "ng\n";}
}

指定した文字列をファイルから検索する
# test.pl
$pattern = shift;
$filename = shift;
open( IN, $filename );
while( <IN> ){
   if( /$pattern/ ){
     print "$.: $_"; # 正規表現と一致して行番号と行の内容
     print "$&\n";  # 正規表現と一致した文字列
     print "$`\n";  # 一致した文字列の前の文字列
     print "$'\n";  # 一致した文字列の後の文字列
   }
}
close( IN );
実行結果
>perl test.pl i test.txt
2: efghijklm
i
efgh
jklm

test.txtの内容
abcdef
efghijklm
lmnopqrst


行番号を付ける

1 $a = 0;
2 $b = 1;
の行番号を付ける

# numadd.pl  行番号をつける
$filename = shift;     # ファイル名
open( IN,$filename );
@a=<IN>;          # ファイルの内容をすべて@a に読み込む
close( IN ); 
$line_num=1;      # 初期化
open (OUT,">$filename");
close (OUT);
open (OUT,">>$filename");
foreach (@a){
  select (OUT);
  printf ("%4d ", $line_num++);
  print ;
}
close (OUT);

行番号を削除

1 $a = 0;
2 $b = 1;
の行番号を削除

# numdell.pl : 行番号を削除
$filename = shift;     # ファイル名
open( IN,$filename );
@a=<IN>;          # ファイルの内容をすべて@a に読み込む
close( IN ); 
@b=();            # 初期化
foreach (@a){
    $_=~ s/\ +\d+\ //;  # スペース、数字、スペース
    push( @b,$_);        # @b の最後尾に追加
}
open (OUT,">$filename");
print OUT @b;
close (OUT);

再帰を使って階乗を計算する

# 階乗を計算する
sub fact {
  my $n = shift;
  $n == 0 ? 1 : $n * &fact( $n - 1 );
}
$a=&fact(4);
print "$a\n";  # 24 と表示

再帰を使ってフィボナッチ関数を計算する

1, 1, 2, 3, 5, 8, 13 .... という直前の2項を足していく数列
         ┌ 1                n = 0
f(n) = ─┤ 1                n = 1
         └ f(n-1) + f(n-2)  n > 1
# フィボナッチ関数
sub fibo {
  my $x = shift;
  ($x == 0 || $x == 1) ? 1 : &fibo($x - 1) + &fibo($x - 2);
}
$a=&fibo(5);
print "$a\n";  # 8 と表示

動作時間を測定する
# フィボナッチ関数
sub fibo {
  my $x = shift;
  ($x == 0 || $x == 1) ? 1 : &fibo($x - 1) + &fibo($x - 2);
}
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
print "開始時刻$hour:$min:$sec\n";
$a=&fibo(40);
print "$a\n";
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
print "終了時刻$hour:$min:$sec\n";
実行結果
開始時刻8:51:12
165580141
終了時刻9:1:46
40個計算するのに、実行時間は10分24秒
(使用CPUは、Celeron(R) CPU 1.50GHz)

ハノイの塔

棒に刺さっている円盤を、次に示す規則に従ってほかの棒に移動させるパズルです。
1.一回に一枚の円盤しか動かせない。
2.小さな円盤の上に大きな円盤を乗せることができない。
3.最初は一本の棒に、大きい円盤の上に小さな円盤が順番に刺さっている。

n 枚の円盤を from から to に移すプログラムは次のように表すことができます。
1.n - 1 枚の円盤を from から via に移す
2.n 枚目の円盤を from から to へ移す
3.n - 1 枚の円盤を via から to へ移す
# ハノイの塔
sub hanoi {
  my ($n, $from, $to, $via) = @_;
  if($n == 1){
    print "$from の円盤 $n を $to へ移動\n";# n 枚目の円盤を from から to へ移す
  } else {
    hanoi($n - 1, $from, $via, $to );# n - 1 枚の円盤を from から via に移す
    print "$from の円盤 $n を $to へ移動\n";
    hanoi($n - 1, $via, $to, $from );# n - 1 枚の円盤を via から to へ移す
  }
}
&hanoi( 3, 'From', 'To  ', 'via ' );
実行結果
From の円盤 1 を To   へ移動
From の円盤 2 を via  へ移動
To   の円盤 1 を via  へ移動
From の円盤 3 を To   へ移動
via  の円盤 1 を From へ移動
via  の円盤 2 を To   へ移動
From の円盤 1 を To   へ移動





―参考文献―
藤沢千壽 著
「すぐわかるPerl」技術評論社 平成11年

おきらくPerlプログラミング入門 -- めざせPerlマスター --



ホームへ