String::Randomでランダム文字列を作成してニヤニヤする

2010-12-25

こんばんは。Songmuです。

さて、テストデータ等でランダム文字列がほしいときがあると思います。そんなときに役立つのがString::Randomです。

引数に独自記法を指定するrandpatternメソッドと、正規表現(のサブセット)を指定するrandregexメソッドに分かれています。とっつきやすいのはrandregexメソッドです。randpatternも自分でルールを追加したり出来るみたいなので、慣れれば便利なのかも知れません

で、String::Randomの情報はググると日本語でもいくつか有用な情報が出てくるので、詳しくはそっちをみてください(ぇ

このモジュールは本来的にはASCIIを出力することしか期待されていません。しかし裏技的な使い方ですが、use utf8してあると、randregexメソッド内に記述したマルチバイト文字を正しくハンドリングしてくれます。また、ブラケットと範囲指定を組み合わせることも可能です。

ということで、以下のようにすると、カタカナ3~9文字のランダム文字列や、漢字3~6文字のランダム文字列を出力させることができます。

use utf8;
binmode STDOUT, ':encoding(utf8)';
use String::Random;
 
my $rand_maker = String::Random->new;
say $rand_maker->randregex('[ーァ-ヶ]{3,9}') for 1..20;
say $rand_maker->randregex('[一-龠]{3,6}') for 1..20;
イジボ
ョガゼペトボテ
イヶヂライペ
ヘヒカミィリッチ
シゥナピ
ヵガアマ
ラバゾヘマグニ
ベヅノダヤオヮ
レギバ
コザヅアデ
モァヮプ
ヂヴーデテォミヱリ
プュメピコフヮズア
ウケグガヶパ
ゲミギ
ナロゴ
ヴペアェフアヮ
コヲギ
スギトツブゼ
タドヱガタヰーハヤ
鳑瑵崒橘瑇忌
笺楩襥褍
髠抛勣估觩
牾僭鸽
紁煲幭衧蝢裣
貸嵫臶褓齯
麈璞雚鏣怯
鬿缯菪
闠善諼枯朮
敌榆鼷禦佸鈖
麏甩瀤熃
碾墰贰
烔謜覯鹝鸷
睆薌痁
掕觤侪宆鬹谔
跇類薧鴙粎喧
鈸姾過猼軋韹
欂乢禛揪椎妺
蚥槯娿鵚诱寮
獹醢後嗘拹

カタカナはなかなか楽しい感じです。漢字はちょっと範囲が広すぎました。

Undocumentedでマルチバイトはテストされておらず、おそらく作者自身もマルチバイトをあまり意識していないと思うので、使うのであれば自己責任で。

で、やはり心配なのでrandregexの実装を見てみると、簡易オートマトンをナイーブに実装していて、指定された正規表現文字列を一文字一文字読み進めてパースしています。ブラケットの範囲指定の場合は、ordで文字の整数値を取得して、その範囲の文字全てを配列に格納して候補文字の集合を作っているようです。なので、マルチバイトが指定されても問題なく動きそうです。

以下最新バージョン(v0.22)の102~119行目部分を引用。

    '[' => sub {
               my ($self, $ch, $chars, $string)=@_;
               my @tmp;
               while (defined($ch=shift(@{$chars})) && ($ch ne "]")) {
                   if (($ch eq "-") && @{$chars} && @tmp) {
                       $ch=shift(@{$chars});
                       for (my $n=ord($tmp[$#tmp]);$n<ord($ch);$n++) {
                           push(@tmp, chr($n+1));
                       }
                   } else {
                       carp "'$ch' will be treated literally inside []"
                           if ($ch=~/\W/);
                       push(@tmp, $ch);
                   }
               }
               croak "unmatched []" if ($ch ne "]");
               push(@{$string}, \@tmp);
           },

randregexはユニコードブロックはおろか、パーレン・パイプも使えなかったりしますが、その分最低限の機能でしっかり動くようにしてあるということなのでしょう。

最終リリースが2006年9月と少し古く、作者のSteven Pritchard氏もこれしかCPANモジュールが無いのが気になりますが、そんなに巨大なモジュールでもなく、podもしっかり書かれていて読みやすく、コードもかっちりしている印象なので、テストデータ作成なんかには十分でしょう。