←戻る

Perlの小技

はじめに

 Perlの長所は手軽で適当なところ……などと、Jは勝手に思っておりますが、そんなPerlの手軽で適当っぷりを見せつける小技を紹介して行きます。まあ、わざわざJが紹介しなくても、ごく当たり前に使われてる技もあったりするんですが、そこはそれ、温かい目で流し読みしてやってください

魅惑の x 演算子

 Perl には、x と言う演算子があることをご存知でしょうか? リファレンスにもしっかり載ってるんで、今さら説明までもないのですが、これは「繰り返し演算子」と呼ばれるものです。例えば、

$result = 'A' x 100;

 ……とすれば、$result には 100 文字の A を代入することができます。でも、案外知られていないのが、配列にも使えると言う点です

open(FILE,">log.txt");
print FILE ("\n") x 1000;
close(FILE);
 こうすると、1000行の空ログファイルも一発で作れてしまいます。もちろん、リファレンスにもちゃんと書いてあるんで、各自で確認してください

ハッシュの要素を配列として扱う

@array = values %hash;

 ……ではありません。念のため(笑)

 ハッシュの要素を配列として扱う技は、リファレンスだと以下のように紹介されていたりします

@values = @hash{ 'key1' , 'key2' };

 これは、以下と同じ意味になります

@values = ( $hash{ 'key1' } , $hash{ 'key2' } );

 しかし、このままだと面白味がありません。そこで、もうちょっと有用性の高い形に作り変えてみましょう

@keys = ( 'key1' , 'key2' );
@values = @hash{ @keys };

 配列は左辺にも書くことができますから、以下のような使い方もできます

@keys = ( 'key1' , 'key2' );
@values = ( 'data1' , 'data2' );
@hash{ @keys } = @values;

 応用すると、CSV レコードの解析などにも使えます

@keys = ( 'datetime' , 'ip' , 'name' );
$csv = "2002-10-17 15:04:30,192.168.0.1,JACKDAW";
@hash{ @keys } = split /,/,$csv;

実行結果で置換

 Perl ではごくあたりまえのことですが、" "(ダブルクォート)で囲まれた文字列は、変数による置換を受けます

$var = 'DEF';
$result = "abc $var ghi ABC $var GHI";
$resultの中身は abc DEF ghi ABC DEF GHI

 文字列中の $var が、変数である$varの内容で、置き換わっていることがわかりますね? これが変数による置換です。それでは次に、「$var の中身を小文字にしてから置換」してみましょう

$var = 'DEF';
$var =~ tr/A-Z/a-z/;
$result = "abc $var ghi ABC $var GHI";
$resultの中身は abc def ghi ABC def GHI

 うまく行きました。次はちょっとややこしくしてみましょう。abc と ghi の間は小文字で、ABC と GHI の間は大文字で置換」します

$VAR = 'DEF';
( $var = $VAR ) =~ tr/A-Z/a-z/;
$result = "abc $var ghi ABC $VAR GHI";
$resultの中身は abc def ghi ABC DEF GHI

 これもうまく行きました。でも、そのために変数 $VAR を増やすことになってしまいました。それに、この例題の条件は「大文字 or 小文字」の単純なものですから、必要と思われるデータを予め作っておくのも、それほど難しいことではありません

 しかし、次のように複雑な条件の場合、「必要なデータを予め作っておく」のは非常に困難となります

  1. タグとタグの間に置かれた変数は < > & を &lt; &gt; &amp; に、改行は<br>に変換してから置換する
  2. <input value="※"> に置かれた変数は < > & を&lt; &gt; &amp; に、改行は&#010;に変換してから置換する
  3. <textarea>と</textarea> の間に置かれた変数は < > & を&lt; &gt; &amp; に変換してから置換する
  4. CGI のオプションに置かれた変数は URL エンコードしてから置換する

 これを解決するのが、これから紹介する「実行結果で置換」する技です。まず、条件 A 〜 D に必要な変換を行う、以下のような関数が用意されているものとします。いずれも、引数に与えられた文字列を変換して返す、単純な関数です

  1. &htmlbodychars( )
  2. &htmlformchars( )
  3. &htmlspecialchars( )
  4. &urlencode( )

 次に、置換したい各所へ、これらの関数を埋め込んだ文字列(テンプレート)を作ります。ただし、関数を埋め込んだ場所は、わかりやすいように {! !} で囲みます

$result=<<'__HTML__';
<html>
<body>
<h1>{! &htmlbodychars($var) !}</h1>
<form action="test.cgi" method="post">
data <input type=text name="data" value="{! &htmlformchars($var) !}">
<textarea name="body">{! &htmlspecialchars($var) !}</textarea>
</form>
<p><a href="test.cgi?data={! &urlencode($var) !}">TEST</a>
</body>
</html>
__HTML__

 最後に、このテンプレートを置換すれば完了です

$result=~s/\{!([^!]+)!\}/eval($1)/ge;
 ちょっと難しい技ですが、変数の内容をそれぞれの場所に適した形で置換できるので、カスタマイズ機能付の掲示板など、大量の変数置換が発生するCGIでは重宝します

※注意!!

 フォームから投稿された文字列を、テンプレートとして使わないでください。{! !}で囲まれた部分は全て Perl のコマンドとして実行されてしまうので、投稿内容によっては、システムに重大な損傷を与える恐れがあります