Perlのエラーメッセージのコーナー。
Perlのエラーメッセージが表示される最小のプログラムを書いて、どういうときにどう怒られるかを研究する。

今回のお題は
Bad evalled substitution pattern
である。

5635 - Milano - S. Maria al Paradiso - Pavimento - Foto Giovanni Dall'Orto - 7-Feb-2008
evalledという言葉は英和辞典にはない。
evalならある。
これはevaluation(評価)の略語であると書いている。

evaluate(評価する)という言葉は、あるもののvalue(価値)を計る、ということだろう。

Perlにはevalという関数がある。
これは、引数(文字列)をPerlプログラムとして評価し、その戻り値を返す。
最も簡単な使い方は、引数を評価して戻り値を印字する。
#! /usr/bin/perl
#
# calc.pl --- 最も安易な電卓プログラム

say eval $ARGV[0];
使ってみる。
$ calc.pl 1+2
3
$ calc.pl '(1+2)*3'
9
$ calc.pl 'sqrt 1+2'
1.73205080756888
1+2、(1+2)*3、√3という式が計算されて表示される。

$ARGV[0]というのはプログラムの第1引数だが、eval関数はそれをPerlのプログラムとして評価する。
1+2という式を評価すると3になる。
(1+2)*3を評価すると9になる。
sqrt 1+2は、sqrt 3で、3の平方根だから、人並みにおごれやで1.73205080756888になる。
前から思ってたけど「人並みにおごれや」ってどういう時に使うセリフだろう。

さて、正規表現のオプションにも/eというのがある。
正規表現によるマッチ、置換の後ろに付けるオプションを修飾子(しゅうしょくし、modifier)と言う。
修飾子と打ち間違えないように注意しよう。
/eという修飾子を置換演算子s///で使うと、置換側がプログラムとして評価される。

まず、/eを使わないプログラムを実験する。
今、下のようなプログラムがあったとする。
#! /usr/bin/perl
#
# eTest.pl --- 消費税を計算したい

use 5.010;
use strict;
use warnings;

while (<DATA>) {
  s/(\d+)/$1*1.08/;
  print;
}

__DATA__
チョコレートは200円です。
ガムは100円です。
建売住宅は20000000円です。
実行する。
$ eTest.pl
チョコレートは200*1.08円です。
ガムは100*1.08円です。
建売住宅は20000000*1.08円です。
このように、__DATA__の下に書いた文の金額部分が「数値*1.08」という数式に変わっている。
  s/(\d+)/$1*1.08/;
がキモだ。

s///演算子は、置換(substitution)を行う。
s/パターン/置換文字列/;
のように書くと、デフォルト変数$_の中で、正規表現パターンにマッチした文字列を、置換文字列で変換する。

\dは数字(digit)1桁(0〜9)にマッチする。
+は量指定子(りょうしていし、quantifire。漁師停止と誤変換しないように注意)というもので、\d+と書くと1桁以上の数字列(数値)にマッチする。
パターンの中に()と書くと、$1、$2、$3。。という変数にマッチした部分が捕獲(キャプチャー)される。
ということで、長々と書いたが、
  s/(\d+)/$1*1.08/;
は、$_の中の1桁以上の数字列を、その数字列の後ろに「*1.08」を付けたもので置換する。

だから、__DATA__の下の
チョコレートは200円です。
という文字列は、
チョコレートは200*1.08円です。
と置換された。

この時点で十分便利という気がするが、やはり数式を計算した答えを出したい。
この場合は、s///演算子をこう変える。
  s/(\d+)/$1*1.08/e;
実行してみる。
$ eTest.pl
チョコレートは216円です。
ガムは108円です。
建売住宅は21600000円です。
あははうまくいった。

これは、置換側の文字列「$1*1.08」、たとえばチョコレートの場合は「200*1.08」を、プログラムとして評価した値にする。
よって、計算結果で置換されたのである。

では、おまちかね、このプログラムで人工的なエラーを発生させてみよう。
#! /usr/bin/perl
#
# eTest.pl --- /e修飾子

use 5.010;
use strict;
use warnings;

while (<DATA>) {
  s/(\d+)/$1*1.08}/e;
  print;
}

__DATA__
チョコレートは200円です。
ガムは100円です。
建売住宅は20000000円です。
実行してみる。
$ eTest.pl
Bad evalled substitution pattern at ./eTest.pl line 10.
これが見たかった!

置換文字列の中に、余計な}が入っていたために、見事エラーになった。

なお、プログラムの間違いの場合によってはこのエラーにならず、余計な}の場合このエラーになるとラクダ本に書いてある。
ラクダ本はつくづく親切だ。