正規表現リテラルをハッシュキーにしたときの動きを探る修行

if, elsif, elsif, ... なコードをどう書き直せばわかりやすいか悩んでいたら、トラックバック & コメントで Regexp::Assemble を教えてもらって、サンプルコードまで教えてもらった。
Regexp::Assembleのバグ? - Humanity
で、話は Regexp::Assemble の add メソッドに渡すものが qr で作ったものではダメ? ということに。

ということで正規表現リテラル(?)じゃなく文字列で渡せばうまくいきました。
でも正規表現リテラルでもできなかったっけ?

そこでちょっと気になったのは、そのひとつ前の段階で、ハッシュキーに正規表現リテラルを使っているところ。ハッシュキーって文字列じゃなかったっけ、だとすると正規表現リテラルをそのコンテキストで使うと内容が変わってしまうかもしれない。とか思ってみた。でも次のエントリでもハッシュキーとして普通に正規表現リテラルを使っている。

とりあえず、次のスクリプトを動かしてみた。やりたいことは、qr で作った正規表現リテラル $re をハッシュキーとしたら、$re 自体に変化が起こるのか、そしてそのキーは文字列 $str とマッチするのか、というところ。

use strict;
use warnings;

my $re = qr{ \A (.+) \z }xms;
my $str = '(?msx-i: \A (.+) \z )';

use Devel::Peek;

print q{-}x10,'before',q{-}x40,"\n";
Dump $re;
my %table = ( $re => 1 );
print q{-}x10,'after',q{-}x40,"\n";
Dump $re;

if ($str eq $re) {
    print $table{$str},"\n";
}

実行結果は次のとおり。

$ perl f.pl
----------before----------------------------------------
SV = RV(0x95b78e0) at 0x95666e4
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,ROK)
  RV = 0x9565d0c
  SV = PVMG(0x957b390) at 0x9565d0c
    REFCNT = 1
    FLAGS = (OBJECT,SMG)
    IV = 0
    NV = 0
    PV = 0
    MAGIC = 0x957bd58
      MG_VIRTUAL = 0x7c8a10
      MG_TYPE = PERL_MAGIC_qr(r)
      MG_OBJ = 0x95a0e98
    STASH = 0x95660fc   "Regexp"
----------after----------------------------------------
SV = RV(0x95b78e0) at 0x95666e4
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,ROK)
  RV = 0x9565d0c
  SV = PVMG(0x957b390) at 0x9565d0c
    REFCNT = 1
    FLAGS = (OBJECT,SMG)
    IV = 0
    NV = 0
    PV = 0
    MAGIC = 0x957bd58
      MG_VIRTUAL = 0x7c8a10
      MG_TYPE = PERL_MAGIC_qr(r)
      MG_OBJ = 0x95a0e98
      MG_LEN = 21
      MG_PTR = 0x95a03a0 "(?msx-i: \\A (.+) \\z )"
    STASH = 0x95660fc   "Regexp"
1

結果からわかること。

  • 正規表現リテラル $re をハッシュのキーとして使うことができる
    • ハッシュキーとして使うと (おそらく文字列コンテキストで使うと) $re の内部状態が変化する
      • MAGIC の MG_LEN, MG_PTR が増えている
    • 文字列として等価な文字列 $str と eq
      • $re で登録したハッシュも $str で引ける

もっと考察を深めるには正規表現の Magic に潜らないとかな。