gvprでの文字列の等価比較

前回のgvprプログラムには、

                    if (length(cs[i]) == length(c) && index(cs[i], c) == 0) {

                        if (length(list[i]) == length(action) && index(list[i], action) == 0) {

のような条件式がif文中にあるが、この式は二つのstring型が等価かどうかを判断している。
gvprではstring型の等価性を比較演算子==!=で比較しようとすると、
マニュアルにあるように演算子の右側の被演算子は正規表現パターンとみなされる。
例えばbash上で試してみると、

$ gvpr "BEGIN{ if ('foo' == 'foo') print('equivalent'); }"
equivalent

$ gvpr "BEGIN{ if ('[foo]' == '[foo]') print('equivalent'); }"

$ gvpr "BEGIN{ if ('[foo]' == '\\\\[foo\\\\]') print('equivalent'); }"
equivalent

なのだ。エスケープの仕方はワンライナではシェルの影響を受ける。したがって、cmdなら、

C:\foo> gvpr "BEGIN{ if ('foo' == 'foo') print('equivalent'); }"
equivalent

C:\foo> gvpr "BEGIN{ if ('[foo]' == '[foo]') print('equivalent'); }"

C:\foo> gvpr "BEGIN{ if ('[foo]' == '\\[foo\\]') print('equivalent'); }"
equivalent

C:\foo> gvpr "BEGIN{ if ('[foo]' == '\\\\[foo\\\\]') print('equivalent'); }"

C:\foo> 

である。
つまり、量指定子などのように文字列がそのまま文字の並びそのものを意味しないようなstringが、
比較演算子の右側に来るような比較をする場合は注意が必要になる。
これに対処する一つの方法は、gsubなどの置換関数で特殊な意味をもつ文字をエスケープしていくことだが、
全てのそのような文字をエスケープするには何種類もの置換が必要である。
そこで別の方法として、string型のaとbの等価性を比較する時に、

length(a) == length(b) && index(a, b) == 0

のような条件式を使うことにした。
長さが一致して、かつ、aに含まれるbの位置がインデックス0から始まることをもって、aとbが等価と判断する。

$ gvpr "BEGIN{ if (length('[foo]') == length('[foo]') && index('[foo]', '[foo]') == 0) print('equivalent'); }"
equivalent

正規表現パターンと演算子一個の簡単な記述で比較できるのはこれはこれで便利である。
文字fの後に一個以上のoが続くstringとマッチさせるなら、

$ gvpr "BEGIN{ if ('foo' == 'f+(o)') print('equivalent'); }"
equivalent

$ gvpr "BEGIN{ if ('foooooo' == 'f+(o)') print('equivalent'); }"
equivalent

$ gvpr "BEGIN{ if ('f' == 'f+(o)') print('equivalent'); }"

$

気をつけなければならないのは、パターンの表記法がkshのパターン表記法であることで、

$ gvpr "BEGIN{ if ('foo' == 'fo+') print('equivalent'); }"

$

はマッチすることを期待したいところだが、
kshのパターン表記法ではないのでマッチしない。
ちなみに、

$ gvpr "BEGIN{ if ('fo+' == 'fo+') print('equivalent'); }"
equivalent

のように、右側の被演算子が正規表現として特別な意味を持たないなら、
正規表現の常としてそれは単に構成文字の連接を意味する文字列として扱われる。
そして、誤った正規表現であり特別な意味を持ち損ねたものの場合は、

$ gvpr "BEGIN{ if ('foo' == 'f+(o') print('equivalent'); }"

$ gvpr "BEGIN{ if ('f+(o' == 'f+(o') print('equivalent'); }"

$ 

のような扱いになる。
f+(oは正規表現エンジンからエラーが報告されてもおかしくない未完成 / 間違い表現である。