ブログトップ 記事一覧 ログイン 無料ブログ開設

サンプルコードによるPerl入門 〜 安定と信頼のPerlを学ぼう 〜

3000-01-01

サンプルコードによるPerl入門 - 目次

 サンプルコードを中心としたPerlの入門サイトです。 Perlを使ったWebサイトの作り方も解説しています。関数やモジュールなPerlの便利な機能の解説も行っています。(スマートフォン、タブレットの場合のPCサイト表示はこちらから行うことができます)

Perl基礎 - Perlの基礎を覚えよう

 Perlの基礎について解説します。Perlのインストール、基本的な構文、配列、ハッシュ、正規表現、ファイル入出力、オブジェクト指向などを学ぶことができます。


  1. コマンドプロンプト- コマンドプロンプトの使い方
  2. Perlとは - Perlの特徴について
  3. Perlインストール - Perlのインストール方法
  4. Perl基礎文法最速マスター - Perlの基礎をすばやく学習
  5. 現代的なPerlの記述方法 - Perlの現代的な書き方
  6. 実践で役立つPerl正規表現 - Perlの正規表現で頻繁に利用するテクニック
  7. 配列とハッシュを自由に扱う - ハッシュと配列の扱い
  8. サブルーチンの作成 - サブルーチンの作成方法
  9. Perlのスコープを理解する - スコープという概念を学習
  10. ファイル入出力の基礎 - ファイルの読み書き
  11. Perlオブジェクト指向入門 - オブジェクト指向の入門
  12. デバッガの手引き - デバッガの紹介
  13. Perl豆知識 - 知っておくと便利な豆知識
  14. Perl FAQ - Perlでよくある質問に答える

Mojolicious入門 - PerlでWebサイトを作ろう

 Mojolicious入門 〜 PerlでWebサイトを作ろう 〜
Perlを学ぶ楽しい方法のひとつはWebサイトを作成してみることです。Webサイトを作成できれば、インターネット上で自分でサービスを公開することもできます。

 MojoliciousはPerlでWebサイトを作る場合の代表的なフレームワークです。Mojoliciousを使えば、簡単にWebサイトを作成することができます。Ruby on Railsを知っている方は、これのPerl番だと考えていただけると想像しやすいと思います。

Perl書籍

 Perl関連の書籍の紹介です。「サンプルコードによるPerl入門基礎編」「簡単プログラミング Perl/CGI」と「もっと自在にサーバを使い倒す 業務に役立つPerl」は僕が書いています。

Perl応用

 基礎を学び終えたら、関数とモジュールについて知るのが、上達の近道です。よく使用する関数や、モジュールについて解説しています。またデータベース操作についても学ぶことができます。

  1. よく使用する関数一覧 - よく使用する関数の紹介
  2. Perlモジュール徹底解説 - モジュールについての詳しい解説
  3. Validator::Customリファレンス - HTMLフォームのバリデーション
  4. SQLiteで学ぶデータベース操作の基礎 - SQLiteとDBIを使ったデータベース操作
  5. DBIx::Customリファレンス - データベースに便利にアクセス
  6. PDLによる統計解析 - PDLモジュールを使った統計解析
  7. PerlプログラマのためのC言語入門 - PerlプログラマのためのC言語の解説です
  8. XSによるC/C++バインディング入門 - PerlからC言語あるいはC++で書かれた関数を呼び出します
  9. Perlその他の情報

Perlリファレンス

Perl逆引き辞典

 逆引き辞典です。やりたいことをさがせます。簡単なサンプルつきです。

コメントデバッグコマンドライン引数配列
ハッシュサブルーチンモジュール数値演算
ビット演算文字列文字コード正規表現
ファイルとディレクトリファイルとディレクトリ(UNIX系OS)ファイル入出力制御構造
変数情報取得日付と時刻開発環境構築
特殊変数プラグマワンライナーPerlとMySQLの連携
自動試験プロセス間通信ソケットオブジェクト指向

Perlその他

CentOS・Red Hat Linux実践テクニック

Perl以外の技術情報

2014-12-20

Perl XSメモリ管理完全マニュアル

 XSのメモリ管理に関するマニュアルです。

Perlのメモリ管理はリファレンスカウント方式

 まず基礎知識としてPerlのメモリ管理は、リファレンスカウント方式によって、行われているということを、知っておいてください。リファレンスカウント方式では、リファレンスカウントが0になった時点で、メモリの解放が行われます。つまり、Perlにおいてメモリ解放を行うということは、リファレンスカウントを0にするという操作を行うことと等しいです。

 リファレンスカウント方式についてもう少し説明しておきます。Perlの変数においては、最初に変数を宣言したときに、その変数のリファレンスカウントは1になります。また、変数への参照が作られると、リファレンスカウントが1増やされます。

{
  # $strのリファレンスカウントは1になる。
  my $str = 'Hello';
  
  # $strのリファレンスカウントは2になる。$str_refのリファレンスカウントは1になる
  my $str_ref = \$str;
}

 またPerlではスコープを抜けると、自動的に変数が解放されます。これは、なぜかというと、変数は、自動的に、モータルと呼ばれる状態になっているからです。モータルという概念は非常に重要です。モータルとは、「スコープを抜けたときに、リファレンスカウントが自動的に1減らされる状態」という意味です。

 上記のコードでスコープから抜けたときに何が起こるかを記述します。

{
  # $strのリファレンスカウントは1になる。
  my $str = 'Hello';
  
  # $strのリファレンスカウントは2になる。$str_refのリファレンスカウントは1になる
  my $str_ref = \$str;
}
# $str_refのリファレンスカウントが1減らされて0になります。
# $str_refのリファレンスカウントが0になったので、$str_refは解放されます。
# $str_refが解放されたので、$strのリファレンスカウントは2から1になっています。
# $strのリファレンスカウントが1減らされて0になります。
# $strのリファレンスカウント0になったので、$strは解放されます。
# ('Hello'は$strの内部に含まれているのこれも解放されます)

 このような経緯をたどって、メモリは解放されます。

XSにおけるメモリ管理の基礎

 次にこれを踏まえてXSにおけるメモリ管理の基礎について解説します。

Perlの変数

 最初にPerlの変数について簡単に解説します。

 Perlの変数について解説しておきます。まず内部的には、スカラ変数は「SV*型」で表現されます。配列は「AV*型」、ハッシュは「HV*型」で表現されます。まずこのみっつを覚えましょう。リファレンスはもちろん「SV*型」に代入できます。そして、内部的には、「AV*型」と「HV*型」は、「SV*型」から派生しているということを、覚えておきましょう。これは、アップキャスト、ダウンキャストができるという意味です。

 スカラ変数の作成は次の関数で行います。XSにおいては、文字列、浮動小数点、整数で、作成する関数が異なるということを覚えておきましょう。

SV* sv_str = newSvPV("Hello", 0);
SV* sv_num = newSvNV(1.2);
SV* sv_num_int = newSvIV(4);

 配列とハッシュの生成は次の関数で行います。

AV* av_nums = newAV();
HV* hv_scores = newHV();

 リファレンスの生成は次の関数で行います。

SV* sv_str_ref = newRV_inc(sv_str);

 他のnewRVという関数もありますが、リファレンスを生成するときは、newRV_incで、リファレンスカウントを1増やすことが原則です。

作成した変数はすべてモータルにする

 次にメモリ管理に進みます。Perlのメモリ管理の鉄則は、新しく作成するPerlの変数は、すべてモータルにするということです。モータルにすることによって、スコープを抜けた変数のリファレンスカウントは1減らされ、自動的にメモリ解放されます。

新しく作成するPerlの変数はすべてモータルにする。

 モータルにするにはsv_2mortal関数を使用します。引数には「SV*型」を受け取り、戻り値はモータルにされた「SV*型」です。

sv_2mortal(SV* sv_var)

 次のように使用します。

SV* sv_str = sv_2mortal(newSvPV("Hello", 0));

 sv_2mortalに「AV*型」「HV*型」などを渡すには、「SV*型」にアップキャストして、さらに受け取るときに「AV*型」「HV*型」にダウンキャストする必要があります。

AV* sv_nums = (AV*)sv_2mortal((SV*)newAV());
HV* hv_nums = (AV*)sv_2mortal((SV*)newHV());

 リファレンスを作成する場合もsv_2mortalを使います。

SV* sv_str_ref = sv_2mortal(newRV_inc(sv_str));

 このように変数をモータルにしておくと、Perlのスコープが終わった時点で、リファレンスカウントが1減らされ自動的に解放されます。C言語のスコープではなくってPerlのスコープが終わった時点なので、区別しましょう。以下のようなXSの関数は、内部的には、関数全体がPerlのスコープで囲われています。

SV*
foo(...)
  PPCODE:
{
  /* Perlのスコープの開始 */
  
  SV* sv_str = sv_2mortal(newSvPV("Hello", 0));
  
  XSRETURN(0);
  
  /* Perlのスコープの終わり */
}

 以下のように戻り値として返したときは、Perlのコードに戻った時点で、リファレンスカウントが1増やされ、モータルになっているのでリファレンスカウントが1減らされるので、結果としてリファレンスカウントは変化しません。

SV*
foo(...)
  PPCODE:
{
  /* Perlのスコープの開始 */
  
  SV* sv_str = sv_2mortal(newSvPV("Hello", 0));
  
  /* スタックに積んで、戻り値として返却 */
  XPUSHs(sv_str);
  XSRETURN(1);
  
  /* Perlのスコープの終わり */
}

配列とハッシュにデータを格納する場合

 上記の鉄則を守りながらコーディングをしていくと、配列とハッシュにデータを格納した場合にメモリ解放がうまくいきません。なぜなら、配列とハッシュは、それ自体が破棄されるときに、内部に含まれる「SV*型」のデータのリファレンスカウントを1下げてしまうためです。

 これを回避するために、配列とハッシュにデータを格納する場合は、リファレンスカウントを手動で1増やしてあげる必要があります。配列の場合は、av_push,av_storeを使う場合、ハッシュの場合はhv_storeを使う場合がこれに該当します。リファレンスカウントを増やすにはSvREFCNT_inc関数を使用します。

/* 配列に格納する場合 */
SV* sv_num = sv_2mortal(newSvIV(3));
AV* av_nums = (AV*)sv_2mortal((SV*)newAV());
av_push(av_nums, SvREFCNT_inc(sv_num));

/* ハッシュに格納する場合 */
SV* sv_score_math = sv_2mortal(newSViv(60));
HV* hv_scores = (HV*)sv_2mortal((SV*)newHV());
hv_store(hv_scores, "math", strlen("math"), SvREFCNT_inc(sv_score_math), 0);

Cの構造体に、Perlのデータを格納する場合

 Cの構造体にPerlのデータを格納する場合は、自分でメモリ管理を行う必要があります。この話の前提として、C言語の構造体をPerlのオブジェクトとして扱う方法を見ていただくとよいと思います。

 C言語の構造体に、「SV*型」を保存したい場合を考えましょう。sv_nameというメンバを持つPeopleという構造体を宣言してみました。

struct People {
 SV* sv_name;
};

 この場合は、代入するときにリファレンスカウントをSvREFCNT_incを使って増やします。そうしなければ、Perlのスコープを抜けた瞬間にリファレンスカウントは1下げられ、勝手に解放されてしまうからです。

SV*
foo(...)
  PPCODE:
{
  /* 省略 */
  
  /* 構造体の作成(ポインタとして作成) */
  People* people = (People*)malloc(sizeof(People));
  SV* sv_name = sv_2mortal(newSvPV("kimoto", 0));
  people->name = SvREFCNT_inc(sv_name);
  
  /* 省略 */
}

 そして、デストラクタの中で、リファレンスカウントをSvREFCNT_decを使ってひとつ下げます。

void
DESTORY(...)
  PPCODE:
{
  // オブジェクトを取得
  SV* people_obj = ST(0);
  
  // デリファレンス
  SV* people_sv = SvROK(people_obj) ? SvRV(people_obj) : people_obj;
  
  // SV*型をsize_t型に変換
  size_t people_iv = SvIV(people_sv);
  
  // size_t型をポインタに変換
  People* people = INT2PTR(People*, people_iv);
  
  // sv_nameを解放
  SvREFCNT_dec(people->sv_name);
  
  // People*を解放
  free(people);
  
  XSRETURN(0);
}

 このようにC言語の世界の構造体(クラスも同じ)のメンバにデータを保存したい場合は、手動でリファレンスカウントの増加と減少を行う必要があります。

まとめ

 まとめると、要点は3つ。

  1. 新しくPerlの変数を作成した場合はsv_2mortalを使って変数をモータルな状態にする。
  2. 配列とハッシュに値を格納するときは、SvREFCNT_incを使って手動でリファレンスカウントを増やす。
  3. 構造体のメンバに保存する場合は、格納するときにSvREFCNT_incでリファレンスカウントを増やし、デストラクタで、SvREFCNT_decを使って、リファレンスカウントを1減らす。

 これで、たいていの場合には対処できると思います。


XSによるC/C++バインディング入門

2014-12-19

Perl自体をソースコードからコンパイルする方法

 Perl自体をソースコードからコンパイルする方法。まず「git clone」でPerlのソースコードをとってくる。

git clone http://perl5.git.perl.org/perl.git

 これは、現在の開発版の最新のブランチです。

 次にREADMEの中に掲載されている次のコマンドを実行します。

./Configure -des -Dprefix=$HOME/localperl

 リリース版だとこのコマンドでMakefileが生成されますが、開発版だと失敗するので次のコマンドを実行します。

./Configure -des -Dusedevel -Dprefix=$HOME/localperl

 次にコンパイルです。makeコマンドを実行します。

make

 次にテストです。

make test

 最後にインストール。「$HOME/localperl」にインストールされます。

make install

 最近僕は、Perlのソースコードをちょっとさわったりするのですが、変更を加えた後に、makeとmake testを走らせるというのは、ちょっと現実的ではない。これは、モジュールの試験も含めて全部やってしまう。

 そこで、最小限のPerlをコンパイルしたり、最小限のテストを実行する方法が用意されています。

 次のコマンドで、miniperlと呼ばれる小さなPerlをコンパイルできます。

make miniperl

 次のコマンドで、小さなテストを走らせることができます。

make minitest

2014-12-10

Perlのデバッガで上下キーがきかずにヒストリー機能を使えない場合の対処法 | Perl逆引き辞典/デバッグ

 Perlのデバッガで上下キーがきかずにヒストリー機能を使えない場合というのがあるかと思います。これは、Term::ReadLine::Gnuがインストールされていないことが原因です。

 Term::ReadLine::Gnuをインストールするためには、以下のC言語のライブラリが必要です。

CentOS,RedHatの場合

yum -y install readline-devel

Term::ReadLine::Gnuのインストール

 cpanmかcpanでTerm::ReadLine::Gnuをインストールします。

# cpanm
cpanm Term::ReadLine::Gnu
# cpan
cpan Term::ReadLine::Gnu


Perl逆引き辞典/デバッグ

2014-11-18

正規表現を利用する | XSによるC/C++バインディング入門

 XS正規表現を使う方法を解説します。ただし、現在、Perlのドキュメントに使用方法が解説されていないので、試し試しでやっているので、間違っていたら教えてください。

正規表現のコンパイル

 XSで正規表現を使用するにはまずpregcomp関数を使って、正規表現をコンパイルする必要があります。これは、正規表現のリファレンスを作成する操作に対応すると考えてください。

# Perl
my $re = qr/[0-9]+/;

# XS (pregcompの第二引数は正規表現のフラグ)
SV* sv_re_str = newSVpv("[0-9]+", 0);
REGEXP* sv_re = pregcomp(sv_re_str, 0);

 REGEXP*型は、SV*型の一種ですので、実際にコードを利用するときはsv_2mortalを使って、自動的にメモリが解放されるようにしましょう。実際のコードで利用するのを想定して書くと次のようになります。

SV* sv_re_str = sv_2mortal(newSVpv("[0-9]+", 0));
REGEXP* sv_re = (REGEXP*)sv_2mortal((SV*)pregcomp(sv_re_str, 0));

正規表現のフラグ

 正規表現のフラグを、pregcompの第二引数に指定することができます。

# Perl
my $re = qr/abc/im;

# XS
SV* sv_re_str = newSVpv("[0-9]+", 0);
REGEXP* sv_re = pregcomp(sv_re_str, RXf_PMf_FOLD | RXf_PMf_MULTILINE);

 フラグの対応は以下です。複数指定する場合はビット演算子の論理和「|」で、フラグをつなぎます。

/mRXf_PMf_MULTILINE
/sRXf_PMf_SINGLELINE
/iRXf_PMf_FOLD
/xRXf_PMf_EXTENDED

正規表現の実行

 正規表現を実行するにはpregexec関数を使用します。pregexec関数の引数は、とても複雑です。

/* pregexec - 文字列に対して正規表現をマッチさせる。 */
I32
pregexec(
  REGEXP * const prog, /* コンパイルされた正規表現 */
  char* stringarg,     /* 文字列のマッチを開始する位置 */
  char *strend,        /* 文字列の終端(NULLポインタの位置) */
  char *strbeg,   /* 文字列の開始位置 */
  SSize_t minend, /* stringarg後のマッチの終端がminend以上でなければならないバイト数 */
  SV *screamer,   /* 文字列をあらわすSV: utf8フラグのためだけに利用される */
  U32 nosave      /* キャプチャしない場合は1を設定 */
)

 マッチが成功した場合は戻り値に真が返ります。サンプルを記述しておきます。

SV* sv_value = sv_2mortal(newSVpv("  12", 0));
char* value = SvPV_nolen(sv_value);

SV* sv_re_str = sv_2mortal(newSVpv("^ *([-+]?[0-9]+) *$", 0));
REGEXP* sv_re = (REGEXP*)sv_2mortal((SV*)pregcomp(sv_re_str, 0));

IV ret = pregexec(
  sv_re, // コンパイルされた正規表現
  value, // 検索開始位置
  value + strlen(value), // 文字列の終端(NULLポインタ)
  value, // 文字列の頭
  0, // 0でOK
  sv_value, // SV*型の文字列
  0 // 0でOK
);

マッチした文字列の取得

 マッチした文字列を取得するにはPerl_reg_numbered_buff_fetch関数を使用します。(非公開のAPIしかないのかな)

# Perl
my $match1 = $1;
my $match2 = $2;

# XS
SV* sv_match1 = newSVpv("", 0);
Perl_reg_numbered_buff_fetch(aTHX_ sv_re, 1, match1); 

SV* sv_match2 = newSVpv("", 0);
Perl_reg_numbered_buff_fetch(aTHX_ sv_re, 2, match2); 


XSによるC/C++バインディング入門