10. Perl で正規表現(2)〜文法 

   10−1  Perl の文法
   10−2  定数・変数
   10−3  構文
   10−4  条件式・パターンマッチ
   10−5  ファイルハンドル
   10−6  特殊なファイルハンドル
   10−7  特殊な変数
   10−8  1行スクリプトとオプション

10−1  Perl の文法

本来それだけで一冊の、いや何冊もの本が書けてしまいますから、詳しくは書籍・ 解説サイト等をあたってください。
大雑把にいうと、文法自体は、C言語、Java、JavaScript などに似ています。 BASIC・VB系(VBVBA、 VBScript)しか知らない人は、馴れるまでちょっとかかるかもしれません。
以下に、テキストファイルを読み込み、正規表現を利用して文字列の検索・置換を行なう作業に 深く関わる部分だけ取り上げて紹介します。

10−2  定数・変数

スクリプト中で文字列を記述する場合は 'abc' または "abc" という形で書きます。 数値を記述する場合は、クォートで囲む必要はありません。
数値・文字列を変数に格納して参照したり計算したりできます。変数名の先頭には $ を付けます。
 $nm1 = 1234;
 $tx1 = "Zaco";
変数 $nm1 に 1234 (数値)を格納します。
変数 $tx1 に "Zaco" (文字列)を格納。

変数に"型"はありません(ですから当然、型宣言もありません)。 数値でも文字列でも受け付けます。
というより、数字をクォートで囲んで文字列として格納しても、その値を使って数値計算ができますし、 逆に、数値が入った変数同士を文字列連結の演算子 . で結びつけることもできます。 要するにナンデモアリです。
 $nm1 = 1234; $tx1 = "4321";
 print ($nm1+$tx1);
 print ($nm1.$tx1);
$nm1 に 1234 (数値) を、$tx1 に "4321"(文字列) を格納します。
$nm1 + $tx1 の結果を画面表示。5555 が表示されます。
$nm1 と $tx1 を連結した文字列を画面表示。12344321 が表示されます。
以下は、上記の演算を1行スクリプトでテストした例です。
(1行スクリプトについては、後述の第8節を参照して下さい。)
 C:\>perl -e "$nm1=1234; $tx1='4321'; print($nm1+$tx1);"
 5555
 C:\>perl -e "$nm1=1234; $tx1='4321'; print($nm1.$tx1);"
 12344321
 C:\>


10−3  構文

Perl の文は ; で区切られます。1行に複数の文を記述することもできます。
 $nm1=1234; $nm1=$nm1*5+1;
代入文。四則演算。
条件分岐もあります。
 if ($nm1 > 0){
     $nm1 * 5;
 }else{
     print "0以下です。";
 }
条件式[$nm1 が0より大きい]が真ならば、
   $nm1を5倍にする。
そうでなければ
   "0以下です。"を画面出力。

繰り返し構文もあります。
 while ($nm1 > 10){
     print "まだまだ。";
     $nm1--;
 }
条件式[$nm1 が10より大きい]が真の間は、
   "まだまだ"を画面出力。
   $nm1を1減らす。

制御構造にはまだまだあるのですが、とりあえず上の2つを知っていれば、 最低限の処理は可能です。

10−4  条件式・パターンマッチ

条件式とは、分岐や繰り返しで判断材料に使われる式で、真(TRUE)/偽(FALSE) いずれかに評価されます。
条件式には以下のような形があります。
(1) 定数はその値自体、代入式は左辺の値が判定値となります。
  その場合、0以外が真、0が偽と見なされます。
 0 1.3 0x2C … 数値:0 は偽、それ以外はの値は真。
 ""  "abcd" … 文字列:空文字列は偽、それ以外の文字列は真。
 $b=$a+3    … $a が-3なら計算結果が0となり偽、それ以外なら真。
(2) 論理式。数値と文字列は別の演算子で判別する点に注意。
 $a == $b …… $a と $b が同じ値ならば真、異なれば偽。
 $a != $b …… $a と $b が同じ値ならば偽、異なれば真。
 $a > $b  …… $a が $b より大きければ真、小さければ偽。
 $a eq $b …… $a と $b が同じ文字列ならば真、異なれば偽。
 $a ne $b …… $a と $b が同じ文字列ならば偽、異なれば真。
(3) 真/偽を返す関数もあります。
 eof(FH1); … FH1 がすでにファイル終端であれば真。
(4) パターンマッチ。
  ここに、本ページの主題である正規表現がからみます。
 $str =~ /zaco/;
 $str =~ /[a-z]+/;
 $str !~ /pattern/;
 !($str =~ /pattern/);
$str が zaco という文字列を含んでいたら、この文全体が真となります。
$str が [a-z]+ という正規表現にマッチする文字列を含んでいたら真。
$str が pattern という文字列を含んでいたら偽、いなかったら真。
上記に同じ。

10−5  ファイルハンドル

ディスク上にあるテキストファイルを Perl の世界に引きずり込むには、ファイルを開いて「ファイルハンドル」 というものを割り当てます。背番号のようなものです。これを通じてファイルの中身を取り出したり、 ファイルの中へ文字列を書き込んだりします。ファイルハンドルは、いわゆる変数とは違うものなので $ は付けません。慣習として、大文字で記します。
 open(FH1, "abcd.txt");
 open(FH2, "> efgh.txt");
 $t = <FH1>;
 print FH2 $t;
 close(FH1); close(FH2);
abcd.txt を読み込み用に開き、以降、ファイルハンドル FH1 で参照します。
efgh.txt を書き込み用に開き、以降、ファイルハンドル FH2 で参照します。
変数 $t に abcd.txt の内容を1行読み込みます。
efgh.txt に $t の内容を書き出します。
2つのファイルを閉じます。
上記3つ目の構文、ファイルハンドルから1行読み込む文は、しばしば条件 式の中で使われます。この文全体が「読み込みができたら真(TRUE)、すでに ファイルの終端に達しているなどで読み込みに失敗したら偽(FALSE)」 とい う評価価値を持ちます。
以下のスクリプトは、非常によく使われる構文です。ファイルから1行ずつ 読み取って所定の処理を繰り返し、ファイルの終端に達した時点で (条件式としては偽となって)処理を終了します。
 open(FH1, "abc.txt");
 while($t = <FH1>){
     print "☆".$t;
 }
 close(FH1);
abc.txt を読み込み用に開きます。
$t に1行読み込み。(失敗したら5行目へ飛ぶ)
   行頭に☆を付加して画面出力。
(2行目に戻る)
abc.txt を閉じます。

10−6  特殊なファイルハンドル

コマンドラインで処理対象に指定されたファイルのファイルハンドルは ARGV と決まっていて、あらかじめ宣言する必要なくいつでも使えます。
フィルタ処理で流れ込んでくるデータの取り込み口は「標準入力」です (デフォルトの入力はキーボードからですが、入力のリダイレクトやパイプによって、 何らかのデータが流れ込んできていることが多いと思います)。 標準入力のファイルハンドルは STDIN と決まっていて、 事前に宣言する必要なくいつでも使えます。 また、コマンドラインで処理対象ファイルが明示されていない場合、ARGVSTDIN と一致します。
出力先ファイルを明示しない時に出力対象となる出口は、「標準出力」です。 (デフォルトの出力先は画面表示ですが、出力のリダイレクトやパイプによって、 ファイルや他のコマンドへ流し込むも多いと思います)。 標準出力のファイルハンドルは STDOUT と決まっていて、 事前に宣言する必要なくいつでも使えます。
◆ コマンドラインで下記のように指定
 C:\>perl abcd.pl efgh.txt
◆ abcd.pl の内容
 $t1 = <ARGV>;
 $t2 = <ARGV>;
 print STDOUT $t2;
efgh.txt から1行読み込みます。
efgh.txt からもう1行読み込みます。
標準出力に2行目を出力します。
上記のファイルハンドルは、スクリプトの中でしばしば省略可能です。
◆ 上記のスクリプトと全く同じ動きをします。
 $t1 = <>;
 $t2 = <>;
 print $t2;
暗黙のうちに ARGV を指定。
同上。
暗黙のうちに STDOUT を指定。
前節までに、「print 〜;」 という文をことわりなしに「〜を画面出力。」と解説してきましたが、 実は 「print STDOUT 〜;」 の STDOUT が省略された形です。

10−7  特殊な変数

Perl にはいくつもの特殊変数が決められていますが、そのうち $_ だけはどうしても 解説を省略することができない重要な変数です。
$_ は、「他の変数が明示されていなければ、暗黙のうちに対象とされている」変数です。 具体的には、以下の場合にデフォルトの変数とみなされます。
(1) while文中におけるファイルハンドルからの読み込み。
(2) パターンマッチ・文字列置換の左辺。
(3) print文の出力内容、その他多くの関数の引数のデフォルトになる。
下の二つのスクリプトは同義です。
 While($_=<ARGV>){
     $_ =~ s/zaco/ZACO/;
     $_ =~ s/ざこ/雑魚/;
     print STDOUT $_;
 }
処理ファイルから1行ずつ $_ に読み込み、
  "zaco" は "ZACO" に置き換え。
  "ざこ" は "雑魚" に置き換え。
  $_ を画面表示する。
(1行目に戻る)
 While(<>){
     s/zaco/ZACO/;
     s/ざこ/雑魚/;
     print;
 }
 同上。

10−8  1行スクリプトとオプション

テキストファイルに保存したスクリプトを指定するのでなく、 コマンドラインに1行スクリプトを書いて済ませる方法を紹介します。1行スクリプトは、
perl -e "スクリプト" [処理ファイル]
という形で指定します。1行とはいえ、 ; で区切って複数の命令を記述することが可能です。
 C:\>perl -e "print 12 * 12;"
 144
 C:\>
"12×12の計算結果を画面表示せよ"という1行スクリプトとその結果。
perl -ne "スクリプト" 処理ファイル という形にすると、 スクリプト
 While(<>){
     スクリプト 
 }
処理ファイルから1行ずつ $_ に読み込み、
  指定されたスクリプトを実行する。
(1行目に戻る)
で囲まれていると見なされます。つまり、下の2つのコマンドライン
 C:\>perl -e "while(<>){ s/zaco/ZACO/; }" abcd.pl
 C:\>perl -ne "s/zaco/ZACO/;" abcd.pl
は、同義です。
perl -pe "スクリプト" 処理ファイル という形にすると、 スクリプト
 While(<>){
     スクリプト
     print;
 }
処理ファイルから1行ずつ $_ に読み込み、
  指定されたスクリプトを実行する。
  $_ を画面表示する。
(1行目に戻る)
で囲まれていると見なされます。つまり、下の2つのコマンドライン
 C:\>perl -e "while(<>){ s/za/ZA/; print; }" abc.pl
 C:\>perl -pe "s/za/ZA/;" abc.pl
は、同義です。
perl -ie "スクリプト" 処理ファイル
という形にすると、加工した結果を処理対象ファイルに書き戻します。もちろん、
perl -ine "スクリプト" 処理ファイル
perl -ipe "スクリプト" 処理ファイル
という組み合わせも可能です。
便利(特に処理ファイルが複数の時)ですが、実行後、元のデータは失われますので注意が必要です。 元のファイルを残したい場合は、
perl -i.bak -e "スクリプト" 処理ファイル
のように、任意の拡張子を付けて残すこともできます。