問題にぶつかると「正規表現を使えばいい」と考える人がいる。
そして、問題を2つ抱えることになる。
--Jamie Zawinski
常に/xフラグを使用する。
これは、確実につかう。JScriptでもXRegExp使ってます。
Xを使うことで、ホワイトスペースが無視され、#も使用できる。そのため、ギチギチに詰められた正規表現である必要がなくて、意味のある単位ごとに、スペースで分けることができる。
もっと分かり易くするには、意味のあるグループごとに改行して、インデントを付け、コメントをつける。
常に/mフラグを使用する
メタ文字^$は任意の行の先頭と末尾にはマッチしない。ほとんどのUnixユーティリティ(sed,grep,awk等)はもともと行思考なので、^$は行の先頭と末尾にマッチするが、Perlではそういった意味はもたない。(JavaScriptでもね!)
Perlでは文字列全体の先頭と末尾を表す。これはプログラマーが通常求める自然な動きではない。/mフラグを使用することで、^$が行単位でマッチするようにすること。
文字列の境界に\A\zを使用する
本当に文字列の先頭と末尾を指定したいときに、/mフラグを外して^$を使用してはいけない。/mは常に使用すること。
代わりに\A\z(小文字のz)が文字列の先頭と末尾を表現してくれる。\A\zは/mフラグの有る無しに関わらず使用することができる。
\Z(大文字)を使わない
\Zは行ベース入力の際に便利だが、\z(小文字)と見分けが付きにくいので、使用しない。\Zは改行とそれに続く末尾にマッチするので、\n? \z を代わりに使用すること。
常に/sフラグを使用する
衝撃的なことにドットは改行にはマッチしない(他の言語でもそうだけど)。これは自然なプログラマの意図とも外れるし、^$との併用でも弊害がでる。例えば{\A (.*?)^}としても^の前は改行であるはずなので、ドットとはマッチしない。
/sフラグを使用することで、ドットは改行とマッチするようになる。本当に改行とマッチさせたくない場合は[^\n]*とすればいい。
自動的に/xmsフラグを挿入する
Regexp::Autoflagsを用いる
正規表現が複数行にまたがる場合は、/.../ではなく、m{ }を使用する
//を使用すると、正規表現が見にくくなる。またxフラグを使用した場合に、問題が生じる。
以下の正規表現はうまく動かない。
m/
set \s+ #キーワード
($IDENT) \s* #Name of file/option/mode
= \s+ #リテラルの=
([^\n]*) #Value of file/option/mode
/xms;
理由はコメント文だと思われている#Name of file/のスラッシュが正規表現の終わりだと判断されているため。コメントはパーサが正規表現を終了したと判断した後に、初めてコメントになる。
{}を正規表現の開始終了のデリミタとして使用すること。{}を使用しても同じ問題が発生するが、コメント文の中に{}が現れる可能性は/よりもずっと低いし、それによって生成されるエラーメッセージはスラッシュのときよりも遥かに分かり易い。
ただし、mapなどのリスト演算ブロックではスラッシュを使用した方がコードが見やすい。
my @counts = map { m{(\d{4,8})}xms } @count_reports; #中括弧が3回もでてくる
my @counts = map { m/(\d{4,8})/xms } @count_reports;
エスケープされたメタ文字ではなく、文字クラスを使用する.
バックスラッシュでエスケープされたメタ文字は、とても見づらい。このため、メタ文字を一文字で構成される文字クラスとして表現する。
\.ではなく、[.]とする。
処理速度に問題がある場合は、名前付き文字を使用する
perlのバージョンによっては、処理速度に問題がある場合があるので、ベンチマークで問題が発覚した場合には、4章で説明した、名前付き文字を使う。
ただし、/xフラグを使用している場合は、名前付きで空白を指定しても、空白は空白なので、ムシされることに注意する。この場合は、文字クラスを使用する。
use charnames qw( :full );
$name =~ m{ harry [\N{SPACE}] s [\N{SPACE}] truman #harry s truman
| harry [\N{SPACE}] j [\N{SPACE}] potter #harry j potter
}ixms;
[A-Z]等、列挙された文字クラスではなく、Unicodeに準拠する名前付き文字クラスであるプロパティを使用する
[a-Z]のような文字クラスはASCIIのアルファベットのみとマッチし、Unicodeのアルファベットにも、Latin-1にもマッチしない。Perl5.6以降の正規表現では\p{}エスケープがサポートされており、Unicodeのプロパティを完全に利用できる。[A-Z][A-Za-z]は、\p{Uppercase}\p{Alphabetic}と表せる。
また言語に依存しないプロパティを使用することもできる。
Readonly my $PERL_IDENT => qr/ [A-Za-z_] \W* /xms;
Readonly my $PERL_IDENT => qr/ \p{ID_Start} \p{ID_Continue}* /xms;
得に便利なプロパティがあり、それはドットメタ文字に対応する\p{any}
コードがとても読み易くなる。
ホワイトスペースが規則通りに入力されることを期待しない
データへの入力としてホワイトスペースが要求されている箇所には\s+を、ホワイトスペースが入力される可能性があるところには\s*を使用する。
0 件のコメント:
コメントを投稿