Perlプログラミングの基礎
Perlプログラムは、CGIプログラムとしてWebサイトでよく利用されています。CGIとは、Webサーバでプログラムを稼働させるための仕組みです。Perlは、ほとんどのレンタルサーバで利用可能です。
目次
Perlの変数について
Perlでは、代入するデータの型に応じて変数の先頭の文字が変わります。またリファレンスと呼ばれる、変数や関数のアドレスを扱うことが出来ます。配列や連想配列(ハッシュ)には、スカラのみを入れておくことが出来ます。多次元配列を作成する場合は、リファレンスで代入します。
Perlには、変数の有効範囲が存在します。通常は my $s のように、ブロック内でのみ有効なローカル変数(レキシカル変数)として宣言を行ってから代入します。他のブロックでも利用したい変数は、our 宣言を使用します。
# コメントは#以降
# スカラ 文字列、数値、リファレンス
$s = 'テキスト';
$s = 123;
# 配列
@a = (1,2);
# 連想配列(ハッシュ)
%h = (a=>'A',b=>'B');
# リファレンス 変数や関数(サブルーチン)のアドレス
$r1 = \$s;
$r2 = \@a;
$r2 = [1,2];
$r3 = \%h;
$r3 = {a=>'A',b=>'B'};
$r4 = \&func;
# リファレンスから変数の取出や関数(サブルーチン)の実行
$$r1;
@$r2;
%$r3;
$r4->();
# ローカル変数(レキシカル変数)
my $my = '';
# グローバル変数(パッケージ変数)
our $G = '';
# デフォルト変数 $_
foreach(@a){
# @aの各値が $_ に入る
print $_;
}
Perlで文字列を扱う方法
文字列の置換や判定では、正規表現を使用できます。正規表現は、文字列内の文字の出現パターンを、文字の集合で特定できる表現方法です。
# 文字列の結合
my $s = $s . $s1;
my $s .= $s1;
# 文字列の一部取り出し
my $s = 'abcdef';
my $s1 = substr($s, 1, 3);#bcd
# 文字列の置換
my $s = 'ababab';
my $s =~ s/a/b/;# 1文字置換 bbabab
my $s =~ s/ab/a/g;# gで全置換 aaa
# リストで変換
my $s = 'ABabab';
my $s =~ tr/ab/12/;#aを1に、bを2に
my $s =~ tr/[A-Z]/[a-z]/;#大文字を小文字に
# 文字列の比較
if ($s eq '') {}#等しい文字列
if ($s ne '') {}#等しくない文字列
# 文字列の判定 数値のみ
if ($s =~ /^\d+$/) {}
# 英数字のみ
if ($s =~ /^[a-zA-Z0-9]$/) {}
# 文字列を区切り文字で配列に
my @a = split /,/, $s;
# 配列を区切り文字で文字列に
my $s = join "\t", @a;
# 小文字に
my $s = lc 'ABC';
# 大文字に
my $s = uc 'abc';
# 文字列を逆順に
my $r = reverse $s;
# 末尾の改行を除去
$s =~ s/[\r\n]+$//;
Perlで配列、連想配列(ハッシュ)を扱う方法
Perlでは、配列と連想配列(ハッシュ)の変数の先頭文字が異なります。また要素にアクセスする場合は、変数の先頭文字が変わってくるので、注意が必要です。また配列の定義は通常 () を用いますが、リファレンスで定義する時は [] を使用します。
# 配列の作成
my @a = ('a','b','c','d');
my @a = qw/a b c d/;
# 配列の要素の取り出し
my $s = $a[1];
# 配列の要素数
my $len = $#a;
# 配列のリファレンスから取り出し
my $r = \$a;
my $s = @$r[1];
# 配列の一部取り出し
my @b = @a[1,2];
# 配列の結合
push @a, @b;
my @c = (@a, @b);
# 配列の先頭から取り出す
my $s = shift @a;
# 配列の最後から取り出す
my $s = pop @a;
# 配列の先頭に追加
unshift @a, 'scalar';
# 配列の最後に追加
push @a, 'scalar';
# 条件で一部要素を取り出す 例では数値の要素のみ
my @m = grep { /^\d+$/ } @a;
# 繰り返し処理
foreach(@a){
# $_ に入る
}
# 変数を指定
foreach my $s (@a) {}
# 配列の要素数でループ
for (my $i=0;$i<$#a;$i++) {}
# すべての要素を変換 例では2倍に
my @r = map { $_ * 2 } @a;
# 昇順に並び替え
@a = sort {$a <=> $b} @a;
# 降順に並び替え
@a = sort {$b <=> $a} @a;
# 配列を逆順に
my @r = reverse @a;
# 多次元配列 要素はリファレンスに
my @a = (
[1,2,3],
[4,5,6]
);
連想配列(ハッシュ)の定義は通常 () を用いますが、リファレンスで定義する時は {} を使用します。注意点としてPerlでは、連想配列(ハッシュ)の順序は保持されないため、順番に処理する場合は、キーなどで並び替える必要があります。
# ハッシュの作成
%h = (a=>'A',b=>'B');
# ハッシュの要素の取り出し
my $s = $h{a};
# ハッシュのリファレンスから取り出し
my $r = \%h;
my $s = %$r{a};
my $s = $r->{a};
# ハッシュのキーリスト
my @keys = keys %h;
# ハッシュの値リスト
my @vals = values %h;
# 繰り返し処理
foreach (my($key, $val) = each %h) {}
# キーの存在判定
if (exists $h{$key}) {}
# 要素を削除する
delete $h{$key};
# キーと値を入れ替える
my %r = reverse %h;
#多次元ハッシュ 値をリファレンスに
my %h = (
a => {k=>'123'},
b => {k=>'456'}
);
Perlの制御構文
Perlのif、else文では、elseifをelsifと記述します。また比較判定時は、数値の場合は==、!=を使用し、文字列の場合はeq、neを使用します。
# 条件分岐
if (A) {
# Aの時、処理
} elsif(B) {
# Bの時、処理
} else {
#A,B以外
}
# ifのみでは後置できる
print $n if $n==1;
# 数値を比較
if (1==1) {} #等しい時
if (1!=2) {} #等しくない時
if (1<2) {} # 大小を比較
# 文字列を比較
if ($s eq '') {} #等しい時
if ($s ne '') {} #等しくない時
# 複数の条件
if (A && B) {} #AかつB
if (A || B) {} #AまたはB
# 条件が偽の時、真
unless (A) {} #Aでない時
# 後置
print $n unless $n==1;
# 指定回数繰り返す
for (my $i=0;$i<10;$i++) {}
# 配列の要素を順番に処理
foreach (@a) {}
# ハッシュの要素を処理
foreach (my($key,$val) = keys %h) {}
# 繰り返し処理を途中で抜ける
foreach(@a){
# 条件Aの時、次へ飛ばす
if (A) { next; }
# 条件Bの時、終わりにする
if (B) { last;}
}
Perlでデータ取得を行なう方法
Perlで、ファイルや標準関数からデータを取得する方法です。CGIなどのWebプログラムでは、環境変数や標準入力からユーザーの入力を受け取ることが出来ます。
# ファイル名を定数に
use constant FILE_NAME => 'data.txt';
# データ用変数
my $lines = '';
# ファイルから1行ずつ読み込む
open FH, '<'.FILE_NAME;
while (<FH>) {
$lines .= $_;
}
close FH;
# ファイルから一気に読み込む
open FH, '<'.FILE_NAME;
my $lines = do { local $/;<FH>; };
close FH;
# ファイルから配列に読み込む
open FH, '<'.FILE_NAME;
my @lines = <FH>;
close FH;
# ファイル情報を取得する
my @info = stat FILE_NAME;
# ファイルの最終更新日時
my $mtime = $info[9];
# ディレクトリ内のファイル一覧
opendir DIR, 'dir/';
my @files = readdir DIR;
closedir DIR;
# ファイルを検索する
my @files = glob '*.txt';
# 標準入力から読み込む
my $buf = do { local $/;<STDIN>; };
# 標準入力から一行ずつ読み込む
my $buf;
while(<STDIN>){
$buf .= $_;
}
# 環境変数から取り出す
my $ua = $ENV{HTTP_USER_AGENT};
# Unixタイムスタンプを取得する
my $time = time;
# 日時を取得する 秒,分,時間,日,月,年,曜日
my($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime;
# 年を西暦に
$year += 1900;
# 月0-11
$mon += 1;
# 曜日
my @week = qw/日 月 火 水 木 金 土/;
$wday = $week[ $wday ];
# ランダムな数値を取得する
my $i = rand 10; #10未満の小数
my $i = int rand 10;#10未満の整数
# 関数(サブルーチン)の引数
sub func {
my($a,$b) = @_;
}
# 引数の先頭から取り出す
sub func {
my $a = shift;
my $b = shfit;
}
# コマンドから返り値を取得する
my @r = qx{ ls -l };
# コマンドラインの引数
@ARGV
# プログラム名
$0
# OS名
$^0
# プロセスID
$$
# プロセスの開始時刻
$^T
# ファイルハンドルの現在の行番号
$.
# スクリプト上の行番号
__LINE__
# スクリプトのファイル名
__FILE__
# パッケージ名
__PACKAGE__
Perlでデータ変換を行なう方法
入力されたデータを出力するために、適切なフォーマットに変換する処理です。初期状態で使うことが出来る標準関数以外にも、標準モジュールが利用できます。標準モジュールは、インストール作業を行なうことなく利用できます。
# 特定の文字列を除去する
# カンマを除去
$txt =~ s/,//g;
# タブ文字を除去
$txt =~ s/\t//g;
# HTMLエスケープする
$txt =~ s/&/&/g;
$txt =~ s/</</g;
$txt =~ s/>/>/g;
$txt =~ s/"/"/g;
$txt =~ s/'/'/g;
# 改行コードの統一
$txt =~ s/\r\n/\n/g;
$txt =~ s/\r/\n/g;
# 末尾の改行を除去
$s =~ s/[\r\n]+$//;
# URLデコードする
$str =~ tr/+/ /;
$str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('H2', $1)/eg;
# URLエンコードする
$str =~ s/([^a-zA-Z0-9 ])/'%'.unpack('H2', $1)/eg;
$str =~ tr/ /+/;
# 文字コードを変換する
use Encode qw/encode decode/;
# Shift_JISの文字列を内部文字列に
$str = decode('Shift_JIS', $str);
# 内部文字列をShift_JISの文字列に
$str = encode('Shift_JIS', $str);
# md5値を求める
use Digest::MD5 'md5_hex';
my $md5 = md5_hex $str;
# 変数を保存用に文字列にする
use Storable qw/freeze thaw/;
# シリアライズ
my $se = freeze \%h;
# 文字列を変数に復元する
my $h = thaw $se;
# JSONデータを変換する
use JSON qw/encode_json decode_json/;
# JSON文字列を変数に
my $j = decode_json($str);
# 変数をJSON文字列に
my $str = encode_json($j);
# ファイル名を変更、移動する
rename 'old', 'new';
# ファイル名を変更、移動する
use File::Copy qw/copy move/;
move 'old', 'new';
copy 'old', 'new'; #コピー
Perlでデータ出力を行なう方法
Perlでファイルにデータを保存したり、出力表示する方法です。CGIなどのWebプログラムでは、ヘッダーを出力後、コンテンツ部分を出力します。コマンドラインのプログラムでは、printで標準出力に出力できます。
# ファイル名を定数に
use constant FILE_NAME = 'data.txt';
# 書き込むデータ
my $lines = '';
# ファイルに保存する 新規書込、上書き
open FH, '>'.FILE_NAME;
print FH $lines;
close FH;
# ファイルに追記する 末尾に追加
open FH, '>>'.FILE_NAME;
print FH $lines;
close FH;
# 読み込んでから保存する ファイルロック
open FH, '+<'.FILE_NAME;
# ファイルロック
flock FH, LOCK_EX;
while (<FH>) {
# 編集、削除処理
$lines .= $_;
}
# 書込位置を先頭に
seek FH, 0, 0;
print FH $lines;
# バッファ出力
select((select(FH), $|=1)[0]);
# ファイルサイズを整える
truncate FH, tell FH;
close FH;
# 標準出力に表示
print 'Hello';
# ブラウザに出力 cgi
print "Content-Type: text/plain\n\n";
print 'Hello';
# 変数の内容を表示する
use Data::Dumper;
# スカラ
print Dumper $s;
# 配列
print Dumper \@a;
# ハッシュ
print Dumper \%h;
Perlの関数(サブルーチン)、クラスの作り方
Perlでは、ユーザーが定義した関数をサブルーチンと言います。引数の受け取り方は、@_またはshiftで受け取ります。$_[0]のように受け取ることも出来ます。関数は、リファレンスとして変数で渡し、受け取り側での実行が可能です。
# 関数(サブルーチン)を作る
sub plus {
my($a1,$a2) = @_;
return $a1 + $a2;
}
print plus(1, 2); #実行
# shift で取得する記述方法
sub plus {
my $a1 = shift;
my $a2 = shift;
return $a1 + $a2;
}
print plus(1, 2); #実行
# リファレンス
my $r = \+
print &$r(3,4);
Perlでは、オブジェクト指向のクラスを実装できます。具体的には、package で名前空間を宣言し、サブルーチン名の重複を防ぎます。コンストラクタは、sub new {} で作成します。デストラクタが必要な場合は、sub DESTROY {} で作成します。
Perlでは、一定の処理を再利用できるようにしたライブラリをモジュールと呼びます。モジュールでは一般的に、モジュール内で定義された関数(サブルーチン)がインポートされて利用できるようになります。クラスファイルもモジュールとして作成できますが、通常メソッドであるサブルーチンはインポートしません。
# クラスを作る
package Base;
# コンストラクタ
sub new {
my $class = shift;
my %args = @_;
return bless \%args, $class;
}
# メソッドA
sub methodA {
my $this = shift;
my %args = @_;
return $args{n} + 10;
}
# メソッドB
sub methodB {
my $this = shift;
my %args = @_;
return $args{n} * 10;
}
# デストラクタ
sub DESTROY {}
1;
継承は、パッケージ変数の@ISAに継承したい基底クラスを代入するだけです。継承とは、オブジェクト指向の考え方で、継承元のプロパティやメソッドを引き継いで利用でき、機能の拡張も行えるものです。
# クラスを継承する
package Extends;
our @ISA = qw(Base);
# メソッドの上書き
sub methodA {
my $this = shift;
my %args = @_;
return $args{n} - 20;
}
1;
Perlのクラス(モジュール)は、useまたはrequireで利用できます。useは、コンパイル時に読み込まれ、サブルーチンのインポートが行われます。requireでは、実行時に読み込まれ、インポートは行われません。
# クラスの使い方
use Base;
use Extends;
my $b = Base->new;
print $b->methodA( (n=>10) );
print $b->methodB( (n=>10) );
my $e = Extends->new;
print $e->methodA( (n=>10) );
print $e->methodB( (n=>10) );