これはMoritz Lenz氏のWebサイトPerlgeek.deで公開されているブログ記事"Perl 5 to 6" Lesson 07 - Regexes (also called "rules")の日本語訳です。
原文はCreative Commons Attribution 3.0 Germanyに基づいて公開されています。
本エントリにはCreative Commons Attribution 3.0 Unportedを適用します。
Original text: Copyright© 2008-2010 Moritz Lenz
Japanese translation: Copyright© 2011 SATOH Koichi
NAME
"Perl 5 to 6" Lesson 07 - 正規表現(またの名をルール)
SYNOPSIS
grammar URL {
token TOP {
<schema> '://'
[<ip> | <hostname> ]
[ ':' <port>]?
'/' <path>?
}
token byte {
(\d**{1..3}) <?{ $0 < 256 }>
}
token ip {
<byte> [\. <byte> ] ** 3
}
token schema {
\w+
}
token hostname {
(\w+) ( \. \w+ )*
}
token port {
\d+
}
token path {
<[ a..z A..Z 0..9 \-_.!~*'():@&=+$,/ ]>+
}
}
my $match = URL.parse('http://perl6.org/documentation/');
say $match<hostname>; # perl6.org
DESCRIPTION
正規表現(Regex)はPerl6で一番改良のあった領域です。Perl5でそうであったほどに正規ではないので、もはやRegular expressionとは呼ばれません。
訳注: タイトルにある通り「ルール」とも呼ばれるようになりました。この記事でもルールと書いてある部分があります。
大きく3つの変更点と改良点があります。
- 整理された構文
- 書き易さを向上させる多くの細かい変更がなされました。例えば
.
はすべての文字にマッチするようになり、今までの意味論(改行以外全部)は\N
で提供されるようになりました。 修飾子は正規表現の頭に付くようになり、キャプチャしないグループは(?:...)
より書き易い[...]
になりました。 - 入れ子のキャプチャとマッチオブジェクト
- Perl5では
(a(b))(c)
のような正規表現はマッチ成功時にはab
を$1
、b
を$2
、c
を$3
にセットしていました。これは変更され、$0
(列挙は0から始まります)はab
、$0[0]
と$/[0][0]
がb
、$1
がc
を保持するようになりました。 マッチ変数はすべて$/
経由でもアクセスできます。これはマッチオブジェクトとも呼ばれ、完全なマッチの木を格納しています。 - 名前付き正規表現とグラマー
- サブルーチンやメソッドのように、正規表現に名前を付けて宣言できます。ルール中で他のルールを
<name>
のように参照できます。 複数の正規表現をグラマーの中に置くことができます。グラマーはクラスのように継承や合成をサポートしています。
これらの変更がルールをPerl5より書き易く、メンテナンスし易いものにしています。
変更点は極めて多岐に渡るので、ここではその上っ面を擦る程度しか紹介できません。
整理された構文
レター文字(アンダースコア、数字とすべてのUnicode letter)はそれ自身にマッチし、バックスラッシュでエスケープされた時は特別の(メタ構文的)意味を持ちます。 それ以外の文字の場合は逆になります——これらはエスケープされないときにメタ構文的な役割を持ちます。
字句通り メタ構文的
a b 1 2 \a \b \1 \2
\* \: \. \? * : . ?
メタ構文的トークンすべてに意味があるわけではありません(今のところは)。未定義の意味を使うのは不正です。
文字列を正規表現中でエスケープする方法がもう1つあります: クォートすることです。
m/'a literal text: $#@!!'/
.
の意味論が変更されたことと、[...]
がキャプチャしないグループになったことは既に述べました。
文字クラスは<[...]>
、否定形の文字クラスは<-[...]>
です。^
と$
はいつでも文字列の先頭と末尾にマッチします。行の先頭や末尾にマッチさせるには^^
と$$
を使って下さい。
これは修飾子/s
と/m
がなくなったということです。修飾子は正規表現の頭に付くようになり、ペアとして書かれます。
if "abc" ~~ m:i/B/ {
say "Match";
}
修飾子は短い形式と長い形式があります。昔の/x
修飾子はデフォルトになりました。つまり、空白は無視されます。
短い形式 長い形式 意味
--------------------------------------------------------------
:i :ignorecase 大文字小文字の違いを無視する(かつての/i)
:m :ignoremark 記号を無視する(アクセント記号、分音記号など)
:g :global 可能な限り繰り返しマッチする(/g)
:s :sigspace 正規表現中の空白が(省略可能な)空白にマッチする
:P5 :Perl5 Perl5互換の構文に戻す
:4x :x(4) 4回マッチする(他の数字でも同様)
:3rd :nth(3) 3番目のマッチ
:ov :overlap :gと似ているが、範囲がオーバーラップしたマッチも考慮する
:ex :exhaustive マッチ可能性をすべて尽くす
:ratchet バックトラックしない
:sigspace
にはもう少し説明が必要です。これはパターン中のすべての空白を<.ws>
(ルールws
を呼び出し、結果を保存しません)に置換します。このルールはオーバーライドできます。デフォルトではワード文字列で囲まれている場合は1個以上の空白にマッチし、それ以外の位置では0個以上の空白にマッチします。
(他にも新しい修飾子はありますが、ここに挙げたものよりは重要ではないでしょう)
マッチオブジェクト
すべてのマッチはマッチオブジェクトと呼ばれるものを生成し、特殊変数$/
に格納します。
これにはいろいろな使い方ができます。真理値コンテキストではマッチ成功時にはBool::True
を返します。文字列コンテキストではマッチした文字列を返し、リストとして使われればキャプチャのリストを返します。ハッシュとして使われると名前付きキャプチャを返します。
.from
メソッドと.to
メソッドはマッチした先頭と末尾の位置を返します。
if 'abcdefg' ~~ m/(.(.)) (e | bla ) $<foo> = (.) / {
say $/[0][0]; # d
say $/[0]; # cd
say $/[1]; # e
say $/<foo> # f
}
$0
や$1
などは$/[0]
や$/[1]
などの単なる別名です。同様に$/<x>
と$/{'x'}
は$<x>
という別名を持ちます。
$/[...]
や$/{...}
でアクセスできるものもまた、マッチオブジェクト(あるいはそのリスト)であることに留意して下さい。
これによってルールの完全な解析木を作ることができます。
名前付き正規表現とグラマー
ルールは旧来のm/.../
で使ったり、サブルーチンやメソッドのように宣言することができます。
regex a { ... }
token b { ... }
rule c { ... }
これらの違いは、token
は:ratchet
修飾子が有効になり(バックトラックしなくなる。Perl5で正規表現の各部を(?>...)
で囲むようなもの)、rule
は:ratchet
と:sigspace
が有効になることです。
このようなルール(どのキーワードで宣言したかに関係なくルールと呼びます)を呼び出すには、その名前を角カッコで囲みます: <a>
。これはサブルールを文字列の現在からマッチさせ、結果を$/<a>
に格納します。つまりこれは名前付きキャプチャです。
結果をキャプチャすることなくルールを呼び出すには、名前の先頭にドットを付けます: <.a>
。
グラマーはルールの寄せ集めで、クラスに似ています(例えばSYNOPSISを見て下さい)。グラマーは継承したり、ルールをオーバーライドしたりできます。
grammar URL::HTTP is URL {
token schema { 'http' }
}
MOTIVATION
Perl5の正規表現は解読不能になることがよくありますが、グラマーは巨大な正規表現を小さな読み易い断片に分割することを促進します。 名前付きキャプチャはルールを自己文書化し、多くのものが以前より一貫性ある形になりました。
最後に、グラマーはPerl6を含むほとんどすべてのプログラミング言語を構文解析できるくらい強力です。 このことがPerl6の構文をPerl5よりメンテナンスし易く、変更し易いものにしています(訳注: Perl6の構文はグラマーを使って定義されている)。Perl5では構文解析器はCで書かれており、構文解析時に変更できませんでした。
コメント
コメントを投稿