はじめに: 本ドキュメントはPerl 6 Apocalypse 5 の日本語訳です。訳についての 質問・意見等は kbk AT kt DOT rim DOT jpまでお願いします。 ExegesisSynoposisも参照してください。

TITLE

Apocalypse 5: パターンマッチング

AUTHOR

Larry Wall <larry@wall.org>

VERSION

  Maintainer: Allison Randal <al@shadowed.net>
  Date: 4 Jun 2002
  Last Modified: unknown
  Number: 5
  Version: 1
  日本語訳最終更新 2004年3月17日

原文はhttp://dev.perl.org/perl6/apocalypse/A05.htmlにあります。

これは我々が"正規表現"(regular expressions)と呼んでいる、 パターンマッチングに関する黙示録(apocalypse)である。この言葉は 我々のパターンマッチングエンジンの性能に連れて成長しており、このため言語学上の 言い争いをここでするつもりはない。しかしわたしは、これを通常"regexes"(わたしが アングロサクソン的なときは"regexen")と呼んでいる。

以下に挙げるのはこの黙示録で取り上げるRFCである。PSAは "problem, solution, acceptance"を表し、そのRFCがPerl6にどのように適用されるかの 個人的なレーティングである。疑いもなくわたしはあなたのRFCを誤ってクラス分けしている が、他のレーティングはそこそこ正確である。 :-)

    RFC   PSA   Title
    ---   ---   -----
    072   aaa   可変長のlookbehind。
    093   abb   Regex: インクリメンタルなパターンマッチングのサポート
    110   bbb   counting matches
    112   acc   正規表現中の代入
    135   acr   マッチを使うときには??や//の場合にも陽にmを要求する
    144   aaa   空の正規表現の振る舞いを単純にする
    145   acr   Perlの正規表現のためのブレースマッチング
    150   acc   マッチしたサブパターンのハッシュを返すための拡張正規表現構文
    156   aaa   first match function (C<?...?>)をマッチコマンドのフラグに置き換える。
    164   ccr   =~, !~, m//, s///, tr//をmatch(), subst(), trade()で置き換える
    165   acc   tr///中での変数を許す
    166   abc   Alternative lists and quoting of things
    191   bbc   賢いcontainer slicing
    197   cdr   正規表現中のNumeric Value Ranges
    198   adr   Boolean正規表現
    261   dbr   perl valuesにおけるパターンマッチング
    274   acc   正規表現に対する一般化した追加
    276   aaa   qr()中の括弧の数のローカライズ。
    308   dar   Ban Perl hooks into regexes
    316   bcr   chunkの処理とprefixマッチングのサポートのための正規表現修飾子
    317   aaa   正規表現に対する最適化情報へのアクセス
    331   acc   $1 と \1 表記の強化
    332   abc   Regex: '/s'修飾子指定時の/$/を/\z/に等価にする
    348   bcc   plain Perl code中の正規表現アサーション
    360   acb   すべてのマッチのlistrefを返すためのmultiply matched groupsを許す
    361   abb   split()を単純化する

興味深いことに、パターンマッチングに関するRFCで撤回されたものはない。 これはcork-brainedなアイデアが提案されたのでも、正規表現文化がすでにcork-brained なアイデアを取り込んでいてcork-brainedであるのでもない。 わたしはわたしのお金がどこにあるのかを知っている・・・:-)

事実、正規表現文化は乱雑で、わたしはそれに対する非難の一部を 共有している。わたしの母はいつもわたしに 身奇麗にしなさいといっていたので、そうするのだ。

For prior Apocalypses, I've used the RFCs as a springboard for discussion of my thinking, but this one is special, because none of the RFCs were courageous enough (or foolhardy enough) to look at the big picture and propose radical change where it's needed. しかしPerlはしばしば読みにくいプログラムを書きがちな 言語であるとみなされ、そしてそれはそうした張本人の正規表現の構文で明らかである。 他の言語が可能な限りな早さでPerlの正規表現を借りたのはおかしなことである。

これは正規表現に関して、Perl 5で我々が果たした大きな飛躍によるところが大である。 大きな飛躍のひとつには、/xオプションによって 正規表現中に空白を使えるようにしたことがある。 それと同様に、拡張構文(?...)による 横向きの飛躍がある。 わたしはこれらを横向きの飛躍と呼ぶが、これらは 機能的な点においては前向きの飛躍でありと同時に可読性の点においては 後ろ向きの飛躍である。 ここで、わたしはこれらすべてを後方互換性(backward compatibility)の名のもとに 正当化した。そしてそのアプローチはその時点では正しいことだったろう。 現時点ではこれは正しいことではない。なぜなら、Perl 6のアプローチは 破壊を必要とするすべてのことを一度に破壊することであるからである。

そして不運なことには、破壊を必要とする正規表現文化が多いということである。

正規表現文化は多様化の面において間違った方向に行っていたが、それに対する非難を するのはわたしの意図するところではない--これに関して非難すべきことは多く、 特定の場面において誰も失敗を犯していない間違いは多い。 たとえば、あなたが現実にキャラクタセットをもはや補足することができないということは 誰の過ちでもない。これはまさにUnicodeが結合キャラクタ(combining characters)を 定義したときのアクシデントである。キャラクタクラスの記法全体は突然変異であり、 正規表現構文の将来におけるちょっとした忍耐をすることになるだろう。

これらのことを踏まえて、あなた方にこの黙示録が過激な方向に行こうとしていることを 注意しておく必要がある。 我々は正規表現文化の幾つかの"神聖な"特徴の変更を提案することになるだろう。 そして、それは我々のより保守的な人たちに対する将来的な衝撃の結果として現れる。 警戒してはいけない。 もしあなたが望むのなら、我々は従来型の正規表現を使ったプログラミングを しつづける方法を提供する。しかしわたしは、幾つかのサンプルを通して ここでわたしたちが提案する変更の大部分を快く思うことを期待する。

RFCがこの黙示録に対するわたしの考えに大きく貢献したことから、わたしは 正規表現文化が行くべき道のわたしのビジョンを最初に述べ、それからそのビジョンに 関連するRFCを調べていくことにしよう。

最初に、現在の正規表現文化における間違ったことがらを列挙してみよう。

ほかにも問題があることはわかっている。しかし、 これはスタート地点である。これから詳細に見ていくことにしよう。

ありすぎる歴史

他の問題のほとんどは、豊かな歴史を取り扱おうとすることから生じる。 今は、歴史に関して間違っていることはないが、間違いを繰り返そうとする不運な 人が歴史の多くの部分がsuboptimalで矛盾に満ちたものであることを覚っている。 Perlは常に可能な限り歴史に合わせるような方向に偏りすぎていた。 そしてその努力が成功することもあった。

文化の連続性は語るべきことが多い。しかし文化の連続性を保とうとすることそれ自体が 非連続的である場合には? Ecclesiastesで述べたように、構築を行うときであり、そして破壊を行うときである。 Perlの最初の五つのバージョンは破壊をすることなくほとんどが構築された。だから、 今は省略したことを正そうとしているのである。

Too compact and "cute"

正規表現は、/aa*b*(cd)*ee/ のような記述を愛するコンピュータ言語学者によって発明されたものである。 こういった記述は概念的なパターンマッチングに関する理由のためになる。 実生活においては、アトムのほとんどは "a" や "b" よりも長い。 実生活においては、トークンはそれが空白で分けられていれば より認識しやすいものである。 考え方としては、/a+//aa*/に還元可能である。 実生活においては、誰かの理論的な潔白を満足させるためにすぎないような15キャラクタのトークン を繰り返そうとは思わない。 そのために我々は"ひとつ以上"を表す量指定子 + のような短縮記法を持っているのである。

ここで、あなたは+がすでにあり、 そして空白を許すために /xが導入されたことを指摘するかもしれない。 ならなぜここで問題にしているのだろう? そう、文化には大きな不活性があり、/xに関する問題とはそれがデフォルトでないことで、 そのために人々は利点が多い場合であってもそれを有効にしようとは考えないということである。 この文化は間違った方向にバイアスがかかっている。 トークンを囲む空白は、例外ではなく標準にすべきものである。 混乱を招く可能性のあるトークンを区切るために空白を使うことを許容すべきである。 記号を多く使った新しい構造を定義することを考慮することはすべきでない。しかし、 我々は(?<=...)(??{...})[\r\n\ck\p{Zl}\p{Zp}]といった構造に慣れてしまっている。 このため、我々は不満を持つことがないのである。 我々は単一キャラクタ文字素に満たされたポットで茹でられようとしているカエルである。 そして、我々はそれを認識していない。

貧弱なHuffman符号化

Huffmanは、一般的なキャラクタを少ないビットで表現し、あまり登場しないキャラクタを 表すにはより多くのビットで表現するというデータ圧縮の方法を発明した。 この原則はもっと普遍的なものであるが、言語デザイナーは 「簡単なことは簡単に。難しいことを可能に」という"別の"Perlのスローガンを 考慮に入れるだろう。しかし、我々はいつも与えられた助言を容れているというわけではない。 ここで、

    (?<=...)
    (??{...})

という二つの正規表現構造について考えてみよう。 日々の使用で一般的なのはどちらだと思う? 長いほうじゃないかな・・・

現在の正規表現においては、貧弱なHuffman符号化の例は多くある。ここで以下の例について 考えてみよう。

    (...)
    (?:...)

グルーピングをすることは捕獲(capturing)することよりも稀なことなんだろうか? そして二つのgobbledygookyキャラクタは価値あるものなのだろうか? このように、同じ長さを持ったそう表現すべきではない構造が数多くある。たとえば

    (?:...)
    (?#...)

が挙げられるだろう。

グルーピングは埋め込みコメントの機能よりも重要である。が、これら二つは 現在のところ同じ長さである。

少なすぎるメタキャラクタに依存しすぎている

A lot of our Huffman troubles came about because we were trying to shoehorn new capabilities into an old syntax without breaking anything. 我々のHuffmanトラブルの多くは新しい機能を何も壊さずに古い構文に押し込めようと していることに起因している。 (?...) 構造は到達点としては成功した。 しかしそれは古い皮袋の中の新しいワインである。もっと成功した例は ものぐさマッチング(minimal matching) *? に関するハックである。しかし、これは 既存の文法の中で動作するように選択するのに 我々がたった三つのキャラクタしか持っていなかったことの問題を示している。 バックスラッシュシーケンスについても似たような問題がある。

言語的な複雑性のwaterbed理論は、どこかを押し下げればほかのどこかが競り上がる と言っている。少数のメタキャラクタに制限しようとしたならば、 ほかのどこかが複雑になるのである。 だから、この複雑さを避ける策はもう少しメタキャラクタを増やすこと であるのが明らかであるとわたしには思えるのである。そしてわたしが増やそうとしている メタキャラクタは・・・いや、これは後回しにしよう。

異なる事柄が同じように見える

以下の構造について考えてみよう:

    (??{...})
    (?{...})
    (?#...)
    (?:...)
    (?i:...)
    (?=...)
    (?!...)
    (?<=...)
    (?<!...)
    (?>...)
    (?(...)...|...)

これらは皆、同じように見える。しかしこれらのうちの幾つかは全然異なることをするのである。 特に、(?<...)(?>...)の反対の意味ではない。 視覚的な問題はLispのごとき括弧の使いすぎにある。 プログラムは違いがはっきりとわかればより読みやすくなる。

貧弱なend-weightデザイン

言語学的には、end-weightの記法は人が短い事柄を先にして長い事柄を後にした センテンスを好む傾向にあると言う考えである。 これは、読んだり聞いたりするときに覚えておかねばならない事柄を少なくする。 Perlはこれを正規表現修飾子で破っている。

    s/foo/bar/g

のように短い場合にはまだ良い。

しかし、RFC 360にあるような場合:

    while ($text =~ /name:\s*(.*?)\n\s*
                    children:\s*(?:(?@\S+)[, ]*)*\n\s*
                    favorite\ colors:\s*(?:(?@\S+)[, ]*)*\n/sigx) {...}

最後にある/sigxを見るまでは、正規表現を どのように読んでいいかわからないのである。 これは実際のところPerl 5の構文解析器で問題になっていて、 空白やコメントの動作を変えるために /x を見つけるまで解析を遅らせなければならないのである。

修飾子に頼りすぎている

先の例にあった /s 修飾子は メタキャラクタ . の意味を変更している。 実際のところ、我々は /s 修飾子 全体を、改行を含むか否かの二つの異なる意味の"任意のキャラクタ"のみの 意味であるのならば許容できた。 同様の議論が /m 修飾子についても適用できる。 正規表現の外にある何かが正規表現の意味を変更するという記法は、 文脈依存であることを考慮しなければならないからではなく意味するところを正規表現の 内部で制御する必要があると言う点において少々いんちき(bogus)である。 そしてこの場合、正規表現の外側で供される文脈は十分なほど正確なものではない。 (Perl 5は文脈の中で制御する方法を持ってはいるが、それはそれ自身曖昧な (?...) 記法を使っている)

正規表現をどのように使うかを制御する修飾子全体は正規表現の外で意味をなす。 しかしend-weight問題はまだ残っている。

多すぎる特殊規則とブービートラップ

文脈を知ることなしに // というパターンが どのように動作するかを知ることはできない。 これは空文字列にマッチするかもしれないし、直前に成功したマッチの内容にマッチするかもしれない。

The local 演算子は正規表現の内と外とでは 異なるふるまいをする。

間違って空パターンを書いてしまうことはとても簡単である。たとえば、 以下に挙げる例ではほかの何でもなく空文字列にマッチする :

    /
    | foo
    | bar
    | baz
    /x

これが意図的なものであった場合でも、そうとは見えない:

    (a|b|c|)

何か見えるものを無効にしようとすることは難しいのでこれは読みづらい。

ドットの複数の意味は混乱を招きやすい。これは ^$ についても同様である。 また、And the opposite of \A の反対の意味を持つものは、しばしば \Z ではなく、\z である。 さらに言えば、いつ \1 を使い、いつ $1 を使うのだろうか? なぜこれらは異なっているのだろうか?

後方参照があまり便利でない

\1 について語るとき、 後方参照には幾つかの欠点がある。The first is actually getting ahold of the right backreference. キャプチャは始まりから番号付けされるので、 数える必要があり、そしてそれは数え間違いを招きやすい。 多くの場合には最後のキャプチャかその前を探すのが可能であれば良いだろう。 もしくは、番号付けの部分をやり直す方法があるといいのかもしれない。

その他の大きな問題とは、あるパターンを検索するものを変形して使うことが簡単でない ということである。開き括弧、開きブラケット、開きカーリーブレースにマッチしたと 考えてみよう。対応する閉じ括弧、閉じブラケット、閉じカーリーブレース を探し出したいと考えたとしても、開きバージョンの括弧類を閉じバージョンのそれに変換する 手段はないのである。なぜなら、後方参照検索は通常の可変マッチング強く依存して実装されて いるからである。そして、それはPerlが $1 を 十分な早さで具体化していないからである。また、Perlが部分正規表現を正規表現から 取り出すのに変数展開に頼っているからでもある。

リテラル文字列にマッチするのが難しすぎる

正規表現はコンパイルされる前に展開パス(interpolation pass)を経るので、 あなたが展開したものはすべて正規表現として取り扱われる。これはしばしば 意図しない結果となるので、klunkyな \Q$string\E メカニズムを使って正規表現のメタキャラクタを 無効化している。そしてそれはなぜならば・・・

二段階の解釈は問題がある

\Q$string\E に関する問題は 正規表現を構築するのに、 変数が参照しているものをどのように扱うかの制御を正規表現にやらせる のではなく展開を使っているという基本的な間違いに起因する。 正規表現は文字列ではなくプログラムである。プログラムの一部分が文字列である という意味においてのみ正規表現は文字列である。 文字列をプログラムとして評価するのに作業しなければならないように、 文字列を正規表現として作業するようにしたほうが良い。大部分の人たちは 正規表現中の変数をリテラルとしてその内容に期待している。 Perlはその予測を破っている。そして予測を裏切っているがゆえに、 $1\1と同一語とすることができないのである。 そして展開された括弧対はキャプチャの数に影響を及ぼすので、サブルールを呼ぶために 展開を使うことが簡単にはできない。これに対処するために (??{$var}) を発明した。しかし このサブルールによってキャプチャされた括弧対を実際に得ることはできない。 分岐点はどんどんある。

弱すぎる抽象化

歴史的に、正規表現は非常に低レベルの言語であって、 正規表現エンジンに対するアセンブリ言語のようなものであると考えられていた。 もしASCIIしか取り扱わないのであれば、 単純に [a-z] はそのままの意味であるので抽象化の必要性は低い。 8ビット文字の登場に伴って、我々はちょっとしたトラブルに巻き込まれ始め、POSIXは ロカールの違いを取り扱うために [:alpha:] の ような名前を考案した。しかし簡潔性の問題に伴うように、 具体的に表現することが可能である抽象的な名前付けに関してバイアスがかかったのである。

しかしながら、名前付けを抜きにしては構文解析器を記述することは不可能に近い。 なぜなら、さまざまなルールがそれぞれを参照することが可能なので文法ルールを 分割する名前を付けることが可能であるようにしなければならないのである。

名前付けすることなしになんらかのUnicodeのサブセットを取り扱うことは困難である。 今日、プログラムの中で [a-z] というものがあれば それは多分まったくのバグである。ASCIIを使っていないエリアでも正しく動作するであろう ことから名前つきキャラクタ属性を使うことはより好ましいことである。

名前を許したとしても、文化のバイアスがかかるためにぶかっこうなものになりやすい。 Perl 5において、名前によってサブルールを呼ぶためには以下のように書かねばならない:

    (??{$rule})

これは四文字以上のキャラクタを持つ。抽象化の不足は 悪いHuffman符号化をもたらす。

名前つきcaptureの貧弱なサポート

リストへの代入を含めないでは、Perlでは"サポートされていない。これは名前付けに 対するバイアスの一部部分である。 代わりに、我々は括弧でのキャプチャを番号付けしそれを数えることを強制されている。 これはリスト代入や $1$fooに 代入することが可能であるときのトップレベルの正規表現においてはまあ問題はない。 しかしこれはネストした正規表現を使おうとし始めたとたんに破綻してしまう。 また、二度以上キャプチャの括弧をマッチさせたときも同様である。Perlは これを最後のマッチのみを返すことで対応している。これは使えないよりはましといった 程度のものである。

ネストしたパターンを使うのが難しい

すでに述べたように、正規表現をそれぞれ参照するようにするのは難しいことで、もし それをやったとしても、その中のネストした情報を取り出すことはほとんど不可能である。 そして、再帰的な定義をしないでは解決できないような構文解析上の問題が存在している。

文法に対する貧弱なサポート

正規表現の中で他の正規表現に対する参照が簡単になったとしても、他の正規表現が 何らかの意味のあるやり方で構成されてはいないという問題がまだある。これは それを囲む文脈上における変数によって解決されるかもしれない。

我々が解析ルールのオーガナイズされたシステムを持っているとき、我々は それを文法と呼ぶ。文法をもつことの利点の一つは、ルールが相互に関係したものとして 成り立っているという仮定に基づいて最適化を行うことができるということである。 たとえば、もしあなたがルールをサブルーチンのみょうちくりんな類のものだと考えていたならば 幾つかのサブルールをインラインにするオプティマイザを記述することができる -- しかしそのサブルールが文法の中で固定されていることを知っているときのみである。

文法クラスのサポートなしには、ある文法から別の文法を導き出す 上品なやり方はない。そしてもし、ある文法から別の文法を導き出せないのであれば 新たな種類の問題を取り扱うような自分自身の言語を生み出すことは容易ではない。

変種の定義に関する無力

もしPerlの派生言語のための別種の文法を持ちたいとして、正規表現に関する ことは? 正規表現はコンパイル時に拡張されるのだろうか? あるいは実行時に 拡張されるのだろうか? Perl 5は正規表現文字列を書き直すための、未発達な オーバーローディング魔術を幾つか持っている。しかし、それはPerl のコードに対する ソースフィルターと同じ問題を抱えている。 すなわち単に生の正規表現テキストを受け取って、そしてそれを自分自身で解析する必要がある ということである。 もう一度繰り返すが、基本的な仮定は正規表現がみょうちくりんな文字列であるということであり、 プログラムを取り囲む命令としてのみ存在するということである

我々は正規表現を、実際の、生きた言語として考えているだろうか?

Poor integration with rich languages

コンピューティングの文化においては、正規表現言語はほとんどの場合 二級市民(second-class citizens)もしくはそれ以下のものとして扱われていた。 CやC++のような"本当の"言語は正規表現を利用するだろうけれども、それは 制限されたアパルトヘイトのポリシーを通したものに過ぎない。正規表現は 我々の召使か奴隷である。正規表現に対して何をするかを指示し、正規表現は それを実行してそれが成功したか否かを返す。

極端な例として、パターンマッチングが言語の制御構造に深く食い込んで組み込まれている PrologやSnobolのような言語がある。 これらの言語は、制御構造の種類に関する考察が実際よりも難しくて コンスタントに使うのに骨が折れるので長期的には成功してはいない。 自由への道はすべての人を奴隷にすることではない。

しかしながら、これら両極端の中間に妥協点があるのではないかと考えたい。 Cのバックグラウンドから、Perlは歴史的に、正規表現を召使とみなしていた。 事実、Perlは正規表現を信頼できる召使として扱ってきていて、Perl社会においては Cのような他の言語よりは良く扱っていた。 にも関わらず、我々は奉仕するための正規表現をco-equalな制御構造として解放したり 我々自身をregexistな態度から免れることができたとしたら、現在よりも より生産的な社会を得ることができるだろう。 我々は正規表現を制御できるようにすることが必要である。 正規表現を呼び出すためのPerlのコードと同じように正規表現がPerlのコードを 簡単に呼び出すことができるようにすることが必要である。

バックトラック制御の欠如

Perl 5 started to give regexes more control of their own destiny with the "grab" construct, (?>...), which tells the regex engine that when it fails to match the rest of the pattern, it should not backtrack into the innards of the grab, but skip back to before it. これは便利な記法であるけれども、問題がある。 第一に、この記法は取るに足らないものである。しかし、あなたはすでにそれを知っている。 第二に、これは十分なものには程遠いものである。 カレントのグルーピングに対してそれを取り消す方法がない。 カレントのルールに対してそれを取り消す方法がない。 これら両方とも正規表現の制御フローに対するfirst-class statusを与えるのに 重要である。

表明を定義するのが難しい

概念的には、正規表現は成功するか失敗するかの表明集合体である。一部の表明は 伝統的な正規表現において表現するのが簡単であるけれども、Perlのような 手続き型言語で表現することがより簡単であるような表明もある。

The natural (but wrong) solution is to try to reinvent Perl expressions within regex language. 自然な(しかし間違った)解決策は正規表現言語におけるPerlの式を再発明しようとする ことである。だから、数値や論理値のための特別な表明式の提案をしている RFCを却下している。より良い解決策とは、正規表現中に埋め込みのPerlの表明を 埋め込むことを簡単にすることである。

Brave New World

現状の正規表現文化に関して否定的な表明をしてきた。ここでクールで知的な トリックをあなたに演じてもらい、すべての否定的な表明を わたしが述べようとしている肯定的な表明にしようと思う。 Damianは彼のExegesis 5において拡大された例について述べていて、それは さまざまな機能がどのように全体をより読みやすくするように働いているかに ついて説明している。

なんにしろ以下に新しい事柄を挙げる。

メタキャラクタの再構成

一部の事柄は変化しない: (...) は以前と同じようにテキストをキャプチャするし、量指定子 *, +, ? も変更されない。垂直バー | は選択肢を分割する。バックスラッシュ \ は後続するキャラクタを通常の解釈から 防御する。? サフィックスはものぐさマッチング (minimal matching)を行う。(これらは広く一般的に使われているキャラクタなので、 変更がなく、通常の正規表現はPerl 5でもPerl 6でも似たようなものになるということに 注意)

今や拡張構文/x がデフォルトなので、 # はコメントを表すメタキャラクタであり、 空白は常に"meta"である。空白は今や一つのトークンと見間違えそうな複数の 正規表現のトークンを区切る標準的な方法である。

キャラクタクラスの中であっても、空白はもはやリテラルとしてはみなされない。 リテラルとして扱いたいのなら、スペースをbackwhackするか、あるいは <sp>, \040, or \x20, \c[SPACE] といったものを使う。キャラクタクラスについて述べよう・・・

もっとも劇的な変化はおそらく[...] をキャラクタクラスを意味するものからキャプチャしないグルーピングに割り当てなおした ことだろう。これは、グルーピングがキャラクタクラスよりも基本的なものであって、 明示したキャラクタクラスは名前つきのキャラクタクラスよりも一般的でなくなった ことに由来する(キャラクタクラスそのものは使うことができるけれども、それは 裸のブラケットを使ったものではない)。

同様に、{...} を汎用化された修飾子から 取り去って、クロージャのデリミタに割り当てた(汎用化された修飾子を使うには <n,m> とするようになった)。

[Update: The generalized quantifier is now **{n..m}.]

わたしは三つの新しいメタキャラクタの意味を変更した。表明のための新しい拡張可能な メタ構文はアングルブラケット<...>を使う。 そしてコロン: は宣言とバックトラッキングの 制御のために使われるようになった(Larryの言語再デザインの法則その2を思い出そう: Larryはコロンを取ったのだ)。コロンは常にそれが囲むものの意味を制御するトークンを導入する。 コロン構文とアングル構文の両方ともが拡張可能である(バックスラッシュ構文も同様に 拡張可能である)。

これは複雑なことのように思われるかもしれないが、実際には単純化しているのである。 ここで、我々は以下のような正規表現のinvariantsを持つようになった:

    (...)       # 常にcapturingグループを区切る
    [...]       # 常にnon-capturingグループを区切る
    {...}       # 常にクロージャを区切る
    <...>       # 常に表明を区切る
    :...        # 常にメタ構文トークンを導入する

(ここで"表明"(assertion)をマッチするかどうか、あるいは それが幅を持つかどうかを意味するものとして使っていることに注意)

[Update: We now also have «...» for non-capturing assertions.]

アングル表明の性質はそれの内側の最初のキャラクタによって制御されるというものである。 最初のキャラクタがアルファベットであればそれは文法的な表明であり、 最初の単語全体が意味を制御する。この単語はもしあれば最初に現在の文法で検索される。 もし見つからなければ、Uncidodeのプロパティクラスによって定義されているものの ように組み込みの文法の一つであるかのように検査される。最初のキャラクタがアルファベット でなければ、現在の文法か、解析ルールを検索するためのPerlの文法もおける 特殊なルールとなるだろう。たとえば、デフォルトでは ! で始まる表明は単なる否定である。 数字で始まる表明は先行するアトムに関する範囲表明(range assertion、<n,m>)であると仮定される。 (これら二つを組み合わせて、<!n,m> のように して範囲を含まないようにすることができる) $, @, %, & で始まる表明は、変数に格納されていたりサブルーチンによって返されたりする 間接的な正規表現ルールの展開として仮定される。括弧で始まる表明は表明として使われる クロージャであるクォートで始まる表明はリテラル文字列のマッチを主張する。

[Update: If the inside character is an angle bracket, it's the ASCII workaround <<...>> for «...».]

メタキャラクタには、今でも使われているが /s 修飾子や /m 修飾子を取り除くために 異なる意味を持っているものがあり、それはPerl 6における大部分の文字列が あらかじめchompされたファイルハンドルに由来するためである。 ^$ といったアンカーは常に文字列の本当の始点、終点を意味する。文字列中に 含まれている行の始点、終点にマッチさせるには ^^$$ を使う。(これらは"愛好家"(fancier)なので二重になっている。これは複数の場所に マッチする可能性があるからであり、また、よりレアな使用法であるからである。Huffman はそういうものは長くするように言っている) ^^$$ は それぞれ ^$ が マッチする場所にもマッチする。

[Update: If the string ends with a newline, the null string following it is not considered a line. So neither ^^ nor $$ match after a final newline. In other words, $$ matches at $ only if there is "extra" text there not terminated by a newline.]

ドット . は常に改行を含めた任意の キャラクタにマッチするようになる(改行以外のものにマッチさせるには \N を使う。もっといいのは、行ごとに 処理していくのであれば自動chompするファイルハンドルを使うことである)。

ある意味では、$, @, %, & といった sigils は、それらが 補間されないので異なるメタキャラクタである。しかし、正規表現エンジンに 解釈させるようになった。このことはリテラルマッチを行うための"補間"(interpolation) することをデフォルトにすることを許すので、lvalue的な構造を埋め込むことができる:

    / $name := (\S+) /
    / @kids := [(\S+) \s+]* /
    / %pets := [(\S+) \: (\S+) \s+]* /

(キャプチャ括弧を伴っている量指定された非キャプチャブラケットの微妙な相互作用、 特に複数の値を得たり複数のkey/valueペアを得たりしていることに注目)

以下はテーブル形式で表したメタキャラクタの違いである:

    旧                    新 
    ---                   ---
    /pat pat #text        /pat pat #text
        pat/x                 pat/              # ほら見て、/xがないよ!
    /patpat(?#text)/       /pat pat <('text')>/ # いつも空白が使える

    /pat pat/             / pat\ pat /          # リテラルとして空白にマッチする
                          / pat \s* pat /       # それをより一般化する
                          / pat \h* pat /       # or horizontally
                          / pat <' '> pat /     # リテラル文字列とする
                          / pat <sp> pat /      # 陽な規則による
                          /:w pat pat/          # 暗黙的な規則による

    /^pat$/               /^pat\n?$/            # ^ と $ は文字列を意味する
    /^pat$/m              /^^pat$$/             # /m はいらない
    /\A...(^pat$)*...\z/m /^...(^^pat$$)*...$/  # \A も \zもない
    /.*\n/                /\N*\n/               # \N は \nの否定
                          /.*?\n/               # これはまだうまく働く
    /.*/s                 /.*/                  # . は常に "any"(任意の一文字)にマッチする

    \Q$string\E           $string               # リテラルとして解釈される

    (?{ code })           { code }              # codeを呼び出し、戻り値は無視する
                          { code or fail }      # codeを表明として使う

    (??{$rule})           <$var>                # $varを正規表現として呼び出す
                          <name>                # 現在の文法からルールを呼び出す

[Update: Follows ordinary scoping rules, so lexical rules take precedence over grammar rules.]


                          <Other::rule>         # ほかの文法からルールを呼び出す
                          <*rule>               # 組み込みのものを呼び出すためにローカルルールをバイパスする
                          <@array>              # alternate rulesの配列を呼び出す
                          <%hash>               # キーワードをルールのキーとして解析する
                          <@array[1]>           # 配列からルールを呼び出す
                          <%hash{"x"}>          # ハッシュからルールを呼び出す
                          <&sub(1,2,3)>         # subによって返された戻り値をルールとして呼び出す
                          <{ code }>            # 無名ルールの戻り値として呼び出す
                          <( code )>            # codeをboolean表明として呼び出す

                          <name(expr)>          # ルールを呼び出し、Perlの引数を与える
                          { .name(expr) }       # 上に同じ

                          <$var(expr)>          # ルールを名前によって間接的に呼び出す
                          { .$var(expr) }       # 上に同じ

                          <name pat>            # ルールを呼び出し、正規表現引数を与える
                          { .name(/pat/) }      # 上に同じ

                          # maybe...
                          <name: text>          # ルールを呼び出し、文字列を与える
                          { .name(q<text>) }    # 上に同じ

    [\040\t\p{Zs}]        \h                    # 水平的空白
    [\r\n\ck\p{Zl}\p{Zp}] \v                    # 垂直的空白
    [a-z]                 <[a-z]>               # 非国際的な等価
                          <alpha>               # より国際的
    [[:alpha:][:digit:]   <<alpha><digit>>      # 組み込みルールのPOSIX クラス

[Update: That must now be written <+<alpha>+<digit>>, or it will be mistaken for «alpha><digit», which doesn't work too well.]

    {n,m}                 <n,m>                 # 繰り返し回数を表明する

[Update: Is now **{n..m} .]

    {$n,$m}               <$n,$m>               # 間接的な繰り返し回数

[Update: Is now **{$n..$m} .]


    (?>.*)                [.*]:                 # [.*]でバックトラックしない
                          .*:                   # アトムに対してはブラケットは必要ない
                          (.*):                 # 同じ。ただしcaptureする
                          <xyz>:                # don't backtrack into subrule

                          :                     # バックトラック時に先行するアトムをスキップする
                          ::                    # バックトラック時にすべての|で失敗する
                          :::                   # バックトラック時に現在のルールが失敗する

                          :=                    # 後続するアトムに名前を束縛する
    my ($x) = /(.*)/      my $x; / $x:=(.*) /   # 正規表現の中で束縛する

    (?i)                  :i                    # 後続において大小文字の違いを無視する
                          :ignorecase           # 同じ。より具体的な形式
    (?i:...)              [:i ...]              # captureすることなしにスコープを限定する
                          (:i ...)              # captureしてスコープを限定する

:iのような宣言は レキシカルなスコープでなんのサブルールにも渡されない。 各ルールは自分自身を含む。 大小文字を無視する動作を戻す組み込みの演算子はない -- 単に異なるルールを 呼び出し、そしてそれが自動的に再び大小文字を区別するようにするのである (パラメータ化されたサブルールが必要なら、アレンジすることができる。これは 結局のところ単なるメソッドである。この表明の回避策は将来の世代のハッカーに 残されている)。

バックスラッシュの再構成

バックスラッシュシーケンスに幾つかの変更が加えられている。キャラクタプロパティ \p および \P はもはや必要とされていない -- あらかじめ定義されているキャラクタクラスは 本来の文法ルールを考慮されるのみである(任意の<...> 表明はその代わりに <!...> を使うことによって 意味を反転することができる)。 以前の黙示録で述べたように、\L, \U, \Q といったシーケンスは それを終端するのに\E をもはや必要としない -- 代わりに キャラクタをブラケット類で囲むことが要求されるようになった。そして、 正規表現のポリシーの変更によって\Q の必要性は 薄れるだろう。事実、これらのシーケンスを使わずに以下のように簡単に書けるのである:

    $(lc $foo)

[Update: And in fact, they did all go away.]

[Update: $() is gone, so you have to say <{lc $foo}> or some such.]

任意のブラケット構造のためには、スクウェアブラケットが好ましいが他のものも使える:

    \x[...]     # 望ましい、単純な bracketing を表す
    \x(...)     # okay, しかしcaptureしない。
    \x{...}     # okay, しかしクロージャではない。
    \x<...>     # okay, しかし表明ではない

\c シーケンスはブラケット構造になったので、 制御キャラクタを表すものから任意の名前付けされたキャラクタを表すものへと拡張された・

\1 のような後方参照はそれを表す変数 $1を使うことが好ましいので排除された。 \A, \Z, \z は、 /s および /m の削除と一緒に削除された。位置表明 \G は より好ましい:c 修飾子の導入とともに削除された。 この修飾子は残っている最後のマッチの位置からの継続を強制する。これは \G が正規表現の先頭を除いてはほとんど使われなかった ことによるものである。正規表現の中で古い最終位置がどこであるのかを表明したいのであれば、 常にカレントポジションをテストすることが (.pos メソッドを使った) 表明によって可能である:

    $oldpos = pos $string;
    $string =~ m/... <( .pos == $oldpos )> .../;

.pos が直前のマッチの最終位置と考えるかも しれないが、それは違っていて、カレントマッチのカレントの位置なのである。 これはつまり、複数回のマッチの間、カレントマッチのカレントの位置はカレントマッチの 最終位置にたまたま同じになることがあるかもしれないということで、最終マッチのときに はそうなる。しかし、別のマッチを始めるとともに、最終マッチはもはやカレントマッチ ではないのである。

:c による継続は先頭からの検索を強制する ような構造においてのみ必要であることに注意すること。サブルールは その初期位置が別のルールで制御されているので自動的にカレント位置で継続する。

[Update: There's also a :p that is like :c but anchors the next chunk to the starting position, so it's good for parsers.]

二つの新しいバックスラッシュシーケンス、\h\v がある。これらはそれぞれ、水平的空白と 垂直的空白にマッチし、Unicodeのスペーシングキャラクタと制御コードを含む。 \r が、理論的にはキャリッジリターンを横に 動かすものであるのに垂直的であるとみなされていることに注意すること。 \n は論理的な改行にマッチして、すべての アーキテクチャーにおける改行キャラクタではない。つまり、 なぜ "n" であって "l" でないかということである。Windowsマシンからマウントされた ファイル上で実行する可能性があるので、プログラムは壊されるべきではない (展開された文字列の中では、\n は今でも 実行されているアーキテクチャにおける通常の改行を生成する)。

    旧                  新
    ---                 ---
    \x0a                \x0a                    # 同じ
    \x{263a}            \x263a                  # ブラケットはあいまいなときにのみ必要となる
    \x{263a}abc         \x[263a]abc             # ブラケットはあいまいなときにのみ必要となる
    \0123               \0123                   # 同じ (今や$123とはあいまいでない)
    \0123               \0[123]                 # ここでブラケットを使うこともできる

    \p{prop}            <prop>                  # プロパティは単なる文法ルール
    \P{prop}            <!prop>

[Update: That's <-prop> now, since <!prop> would be a zero-width assertion.]

    [\040\t\p{Zs}]      \h                      # 水平的空白
    space               \h                      # 正確ではないがしばしば正しい
    [\r\n\ck\p{Zl}\p{Zp}] \v                    # 垂直的空白

    \Qstring\E          \q[string]
                        <'string with spaces'>  # リテラル文字列にマッチする
                        <' '>                   # リテラルスペースにマッチする

    \E                  削除                    # \Q[...] を代わりに使う

[Update: \Q[...] is also gone. Use <{quotemeta ...}>.]

    \A                  ^                       # ^ は今や不変である
    \a                  \c[BEL]                 # アラーム (ベル)

    \Z                  \n?$                    # 明確に
    \z                  $                       # $ は今や不変である
    \G                  <( .pos == $oldpos )>   # 特定の位置でマッチする
                                                # 典型的には m:c/pat/ で使う

[Update: Or m:p/pat/.]

    \N{CENT SIGN}       \c[CENT SIGN]           # 名前つきキャラクタ
    \c[                 \e                      # エスケープ
    \cX                 \c[^X]                  # 制御キャラクタ
    \n                  \c[LF]                  # 改行を特定する
    \x0a\x0d            \x[0a;0d]               # CRLF
    \x0a\x0d            \c[CR;LF]               # CRLF (推測)
    \C                  [:u0 .]                 # utf8でバイトを強制する(危険)

[Update: The Unicode levels are now specified by :bytes, :codes, :graphs, and :langs, not by numeric level.]

    [^\N[CENT SIGN]]    \C[CENT SIGN]           # CENT SIGN以外の任意のキャラクタ

    \Q$var\E            $var                    # 常にリテラルと仮定されるので、
    \1                  $1                      # $1はリテラルの後方参照
    /$1/                my $old1 = $1; /$old1/  # ここでは一時的に使わなければならない

    \r?\n               \n                      # \n は論理的な改行を表明する

    [^\n]               \N                      # 論理的な改行ではない
                        \C[LF]                  # 改行ではない

    [^\t]               \T                      # タブではない(以下は推測的)
    [^\r]               \R                      # 復帰ではない
    [^\f]               \F                      # 改ページではない
    [^\e]               \E                      # エスケープではない
    [^\x1B]             \X1B                    # 指定された十六進キャラクタではない
    [^\x{263a}]         \X[263a]                # Unicode SMILEYではない

    \X                  <.>                     # 文字素 (結合されたキャラクタ並び)
                        [:u2 .]                 # レベル2+において、ドットは文字素を意味する

[Update: That's :graphs now.]

レベル2のUnicodeサポートでは、ひとつのキャラクタは文字素であると 仮定される。つまり、0個以上のcombining charactersが後続するベースキャラクタの並びである。 このことはキャラクタ. の意味に影響するばかりでなく、 否定形のキャラクタは実際には単一のキャラクタの全探索が後続するnegative lookahead assertion なので、否定形のキャラクタにも影響する。 たとえば、\Nは実際には以下のような意味となる:

    [<!before \n> . ]

このため、\n に実際にどのくらいの キャラクタがマッチしたのかは意味がない。結局のところ \Nは常に単一の文字である・・・

修飾子の再構成

もうコロンを正規表現の区切りとして使うことはできない。なぜならば、 正規表現修飾子は正規表現構造の前にもおくことができるようになったからだ:

    s:w:i:e /foo/bar/           # :words :ignorecase :each

これは次のように書くこともできる:

    s/:w:i:e foo/bar/           # :words :ignorecase :each

単一文字の修飾子は次のようにまとめて書くことができる:

    s:wie /foo/bar/             # :words :ignorecase :each

[Update: Bundling is no longer allowed. Whitespace is allowed.]

しかしそれは、長い修飾子を解決する際の曖昧さを解決するために、 そのシーケンス全体がすでに定義されている長い修飾子と衝突しないときのみのことである。 長い修飾は他の修飾子とまとめることはできない。このため以下の書き方は有効である:

    s:once:wie /foo/bar/

[Update: Not any more.]

しかし以下の例はダメである(あらかじめそれを定義していない限り):

    s:wieonce /foo/bar/
    s:oncewie /foo/bar/

コロンが正規表現の区切りとしてつかえなくなったのと同様に、もはや括弧を 区切りとして扱うこともできない。これによりパラメータ化された修飾子が可能となる:

    s:myoption($x) /foo/bar/

このルールはまた、 s/// を 関数 s() と、 tr///tr() と異なるものとするようなことを許す。もし区切りとしてのマッチングブラケットが必要ならば、 スクエアブラケットを使うことをお勧めする。これは今やキャプチャ抜きのグルーピングを 意味するものだからだ。

[Update: Parens may be used for delimiters as long as they are not adjacent to the final option. They may be separated with either a colon or whitespace.]

/x, /s, /m といった修飾子はもはや必要ではなくなり、 引退した。/o が必要かどうかは明確でない。 と扱うことのできない問題を捕らえるということがなければ、これもなくなるだろうと 仮定している。標準の展開の奇妙な動作をもはや受けないので、サブルールをキャッシュしている ときに正規表現はより多くの制御をすることに注意すること。

古い /c 修飾子は、 正規表現が失敗したときに決して位置をリセットしなくなったのでなくなった。 位置のリセットを行うには、$string.pos = 0 と陽に設定してやる。しかし、文字列に対する代入は自動的にその位置情報を 0 にリセットすることにも注意すること。 このため、典型的なループ中の任意の文字列はカレントの検索位置としてあらかじめ 0 が設定されているものとして開始される。 その場での(in place)文字列の変更は、 位置が置換されるなかにあったならばデフォルトでその位置を置換の末尾に移動させる (これはs/// のセマンティクスと一致している)。

/e 修飾子もなくなった。これはこの修飾子が reverse parsing magic をしていたためで、:e:each の短縮形となる -- 後述する。 それでも式の値に置き換えるのは次のように簡単にできる:

    s/pat/$( code )/;

もしくはこうする

    s(/pat/, { code });

[Update: :each is gone, and we're back to :global and :g to stay with common culture. Since $() is also gone, just interpolate code using a closure: s/pat/{ code }/.]

新しい修飾子 :once がある。これは マッチをただ一度だけ成功させるものである(従来の ?...? と同様)。これをリセットするには、正規表現オブジェクト で .reset メソッドを実行する (もし名前つき正規表現オブジェクトがなければひどいことだ)。

もう一つの新しい修飾子 :w は パターンの中でリテラルの空白が現れたときはいつでも空白に暗黙裡にマッチするように する。言い換えれば、パターンの中の実際の空白の並びを \s+ (二つの識別子の間) もしくは \s* (その他のものの間)で置き換えるということである。 だから、

    m:w/ foo bar \: ( baz )*/

が意味するところはPerl 5形式で表せば以下のようなことである:

    m:p5/\s*foo\s+bar\s*:(\s*baz\s*)*/

[Update: The optional whitespace is actually matched by the «ws» rule, which you can redefine to change the semantics of :words.]

明白に述べられた任意の空白マッチングのトークンは暗黙裡に空白にマッチしないように ルールを拡張したので、:w の元での 空白の扱いを制御することが可能である。だから:

    m:w/ foo\ bar \h* \: (baz)*/

が意味するところはPerl 5形式で表せば以下のようなことである:

    m:p5/\s*foo bar[\040\t\p{Zs}]*:\s*(baz)*/

ここで

    /[:w foo bar]/

の最初の空白は"foo"の前にある \s* にマッチする。 これは通常は望んだ動作だろうが、それを望まない場合ちょっとした問題がある。 次のように書くことができないのである:

    /[:wfoo bar]/

これは:wfoo 修飾子を検索しようとしてしまうために うまくいかない。しかしながら、幾つかの回避策がある:

    /[:w()foo bar]/ 
    /[:w[]foo bar]/ 
    /[:w\bfoo bar]/ 
    /[:w::foo bar]/

最後の一つは見せ掛けの :: 演算子である。 バックトラックするであれば、ブラケットをそのままにしておけるので、実際には なにもしないことになる。

新しい :c/:cont 修飾子は正規表現に文字列中のカレント位置で続けることを 強制する。これは正規表現の外でのみ使われるだろう(そう、正規表現の内側で使うことも できるが、それは冗長である)。この修飾子はまた、正規表現に 次の可能な事柄にのみマッチすることを強制する。これは ^ アンカーと同じではない。なぜなら、 m//s/// によって行われる暗黙的な走査だけが禁止されるので、最初の繰り返し以外でも動作する からである。言い換えればこの修飾子はすべてのマッチが引き続いた(contiguous)ものであることを 強制する。だから、 :c は"continue" と "contiguous" の両方の 短縮形なのである。次のようにした場合、

    $_ = "foofoofoo foofoofoo";
    s:each:cont/foo/FOO/;

結果はこうなる:

    FOOFOOFOO foofoofoo

これは奇妙なものに思えるかもしれないが、任意の埋め込み正規表現のセマンティクスと 同一である:

    $_ = "foofoofoo foofoofoo";
    $rx = rx/foo/;
    m/<$rx>*/;          # "foofoofoo"にマッチする

[Update: Now we use :p /:pos to get contiguous semantics. The :c /:continue modifier starts scanning again each time, so when used with :global it really only influences where the first match is found.]

数字で始まる修飾子はパターンに複数回マッチするようにする。これは正規表現の外でのみ 使うことができるだろう。ordinals と cardinals は区別されるので、 バンドルすることはできない。つまり、数字に続くキャラクタに依存して複数回マッチが どのように扱われるかということである。次のようにした場合、

    s:3x /foo/bar/

最初の三つのインスタンスを変更する。しかし次のようにすると

    s:3rd /foo/bar/

三番目のインスタンスだけを変更する。次のように書くこともできるが

    s:1st /foo/bar/

but that's just the default, and should not be construed as equivalent to :once, which matches only once, ever. (Unless you .reset it, of course.) これはデフォルトの動作であり、ただ一度だけマッチする :once と同じであると 解釈すべきではない(もちろん .reset しない限りにおいて)。

cardinals と ordinalsを組み合わせることもできる:

    s:3x:3rd /foo/bar/

これは三番目、六番目、九番目を変更する。To change every other quote character, say

    s:each:2nd /"/\&rquot;/;

:each:3x と似たようなものである(3が大きな値になったもの)。 実際には :each は可能なすべてのマッチを生成する のではないということに注意すること。これはオーバーラップを許していないためである。 すべての可能なマッチを得るには、 :any 修飾子を 使用する。以下の例:

    $_ = "abracadabra";
    @all = m:any /a[^a]+a/;

は次のような結果を生成する:

    abra aca ada abra

これは正規表現の処理の残りがある限り同じ場所で複数回マッチすることもあるので、次の例:

    @all = m:any /a.*?a/;

は以下の結果になる:

    abra abraca abracada abracadabra aca acada acadabra ada adabra abra

次のようにした場合

    $sentence.m:any /^ <english> $/

english ルールに従ったセンテンスの可能な解析結果を 得ることになる(Englishのルールと混乱しないように)。

[Update: :any has been replaced with :overlap and :exhaustive to differentiate the cases of wanting one solution at each position from wanting all solutions at every position.]

Unicodeサポートのさまざまなレベルを示すために以下に挙げる修飾子がある。これらは 正規表現の内側と外側のいずれでも使うことができる:

    :u0         # バイトを使う      (. はバイト)
    :u1         # レベル 1 サポート (. はコードポイント)
    :u2         # レベル 1 サポート (. は文字素)
    :u3         # レベル 1 サポート (. は言語依存)

これらの修飾子はデータの状態については何も言及しないが、一般的なPerlの内部的な データはすでに Normalization Form C であるので、 :u1 を指定した場合でもprecomposeされた キャラクタは正しく振舞う。これらの修飾子はデフォルトのサポートレベルを 上書きすることに注意すること。おそらくファイルの先頭でプラグマによって設定されるだろう・

[Update: Replaced with :bytes, :codes, :graphs, and :langs.]

最後に、 :p5 修飾子がある。これは 正規表現(もしくはグループ)の残りの部分を、 文字列展開も含めてPerl 5の正規表現であるかのように 解析するようにする(しかしPerl 5の後置修飾子を使うことはできない)。

[Update: Now spelled out :perl5.]

    旧                  新
    ---                 ---
    ?pat?               m:once/pat/             # 一度だけマッチする
    /pat/i              m:i/pat/                # 大小文字の違いを無視する
                        /:i pat/                # 大小文字の違いを無視する
    /pat/x              /pat/                   # 常に拡張
    /pat\s*pat/         /:w pat pat/            # 語の並びにマッチ
    /(?i)$p5pat/        m:p5/(?i)$p5pat/        # Perl 5 構文を使う
    $n = () = /.../g    $n = +/.../;            # 出現頻度を数える
    for $i (1..3){s///} s:3///;                 # 三回行う
    /^pat$/m            /^^pat$$/               # /m はもういらない
    /./s                /./                     # /s はもういらない
    /./                 /\N/                    # . は /s のように動作する

キーワードとコンテキストの再構成

遅延正規表現 (deferred regex) ルールが qr// ではなく rx// によって定義された。これは 正規表現がもはやクォートされた文字列の一種だからである。

実際には、即座に実行されるコンテキスト中でなければ、 sub, 任意の // もしくは rx// を陽に使って遅延正規表現を 宣言することなくクロージャを定義することが可能である。 正規表現はそれがboolean コンテキスト、numeric コンテキスト、もしくは文字列コンテキスト にある場合には自動的に実行される。しかし型付けされていない変数に対する代入や 関数に渡される型付けされていないパラメータとしての正規表現は そのようなコンテキストではない(もちろん陽に宣言されたRULEパラメータは評価コンテキスト を提供しない)。

そのため以下の例は等価である:

    my $foo = /.../;            # 正規表現オブジェクトを作成する
    my $foo = rx[...];          # 正規表現オブジェクトを作成する
    my $foo = rule {...};       # 正規表現オブジェクトを作成する

同様に以下の例は等価である:

    @x = split /.../;
    @x = split rx[...];
    @x = split rule {...};

[Update: Note that split supplies an implicit :c here.]

"rule" 構文はそれがサブルーチンやメソッドであるかのように遅延正規表現を宣言する 方法である。

遅延正規表現を即座に評価することを強制するために、適当な単項演算子を使うことができる。

    my $foo = ?/.../;   # booleanコンテキスト。 マッチしたかどうかを返す
    my $foo = +/.../;   # 数値コンテキスト。マッチした数を返す
    my $foo = _/.../;   # 文字列コンテキスト。capturした/マッチした文字列を返す

[Update: Unary _ is now unary ~.]

標準のマッチ形式と置換形式は同様に、コンテキストに関係なく即座の評価を強制する:

    $result = m/.../;           # トピック文字列上でマッチを行う
    $result = s/.../.../;       # トピック文字列上で置換を行う

これらの形式はまた、あたかも暗黙に.*? が 各繰り返しの前にがあるかのように、 正規表現に文字列の最初でマッチングを始めることと マッチのために文字列を前方にスキャンすることを強制する (これらの動作は両方とも、:c/:cont 修飾子を使うことで抑制することができる)。 対照的に、遅延形式 (deferred form)の意味はコンテキストに依存する。特に、 遅延正規表現はサブルールとして使われたときに :c が仮定される。 つまり、それは最後のマッチを継続し、文字列の先頭において 次のものが正しくマッチするようにする必要があるということである。

[Update: A regex actually assumes :p semantics when used as a subrule. And the long form of :c is :continue.]

その他のコンテキストにおいては、リストコンテキストを含め、遅延正規表現は 即座に評価されることはない。しかし、正規表現オブジェクトのリファレンスを 生成する:

    my $rx = /.../;     # 評価されない
    my @foo = $rx;      # エラー: 型が合わない。
    my @foo = ($rx);    # 単一の要素。正規表現オブジェクト。
    my @foo = (/.../);  # 同様。
    my @foo := $rx;     # @fooにautogrowルールをセットする。

リストコンテキストにおいて繰り返し評価を行うには、正規表下のオブジェクトを その他のイテレータとして取り扱う:

    my @foo = <$rx>;

より明確な形式を使って記述することもできる:

    my @foo = m/<$rx>/;

これらは同一のものではない。なぜなら、前者は:c を仮定し、unmentioned topic のカレントポジションで開始するのに対して、後者は スキャンを始める前にポジションをリセットしているからである。 同様に、遅延正規表現は :c 修飾子を仮定する ので、<$rx>m// のようには文字列をスキャンしない。 これは複数の値をリストに返すことができるが、それらは隣接したものである必要が ある。.*? を伴ったパターンを前置することによって m// のスキャニング効果を得ることができる。

[Update: Where the preceding paragraphs says :c read :p.]

しかし、この基本的な変更を理解することは非常に重要である。 // はもはやm// の短縮形ではなく、rx// の短縮形である。 // に修飾子を付加したいのであれば、 m// ではなくrx// に対して使う必要がある。次のように split を 呼び出すことは今では間違いである:

    split m/.../

(つまり、パターンマッチの戻り値をsplitの区切りとしてのリテラルとして扱うことを 望んでいるのでない限りこれは間違いである)

古い ?...? 構文はなくなった。実際には、 単項の ? を得るようになる。

    旧                  新
    ---                 ---
    ?pat?               m:once/pat/
    qr//                rx//
                        rule { }

空文字列の再構成

空パターンは不正なものとなった。空パターンを使ってマッチを行いたいのなら 次に挙げるもののいずれかを使用する:

    旧                  新
    ---                 ---
    //                  /<prior>/       # 先行してマッチしていたものにマッチする
    //                  /<null>/        # キャラクタの間の空文字列にマッチする
    (a|b|)              (a|b|<null>)    # null alternativeにマッチする

表明したように、<null> は常に成功するという ことに注意。次のように書くことはできない:

    / <null> | single | double | triple | home run /

なぜならこれでは決して一塁にたどり着くことはないからである。

拡張構文の再構成

すべての (?...) シーケンスはもはやなくなった。 なぜなら、括弧はいまや常にキャプチャするからである。置き換えたシーケンスは <...> から内在するスコーピングを取る。 一方で、他のものは別のブラケットキャラクタかブラケット構造を構成することのできる 任意のアトムに結びつけられる。Perl5からPerl6へのトランスレータの展望からの メタシンタクス問題をみたとき、以下はそういったPerl 5の拡張構造の変換結果である:

    旧                  新
    ---                 ---
    (??{$rule})         <$rule>         # 変数の中の正規表現を呼び出す
    (?{ code })         { code }              # Perl codeを呼び出し、結果を無視する
    (?#...)             <('...')>       # インラインコメント。ほとんど必要ない
    (?:...)             [...]                 # captureしないブラケット
    (?=...)             <before ...>    # 肯定先読み
    (?!...)             <!before ...>   # 否定先読み
    (?<=...)         <after ...>     # 肯定後読み
    (?<!...)         <!after ...>    # 否定後読み
    (?>...)          [...]:                # grab (任意のアトム)

    (?(cond)yes|no)     [ cond :: yes | no ]
    (?(1)yes|no)        [ <(defined $1)> :: yes | no ]

<$rule> 構造は、 変数 $rule に格納された別の正規表現の "遅延した"呼び出しを行う。それが正規表現オブジェクトであれば、あたかもそれが サブルーチンであったかのように呼び出されるだけなので、パフォーマンスに関する問題はない。 文字列であった場合には、正規表現としてコンパイルされそして実行される。コンパイル済み フォームは文字列のプロパティとしてキャッシュされるので、文字列を変更しない限り 再コンパイルする必要はない(これはそのベースオブジェクトが変更されたときに自分自身を 無効化するプロパティを持つことが可能であるということを暗に示している)。その他の場合、 評価された正規表現はサブルールとして取り扱われ、すべてのキャプチャは その外側の正規表現が文字列を回復しようとするステップを取らない限り、外側の正規表現 に対して不可視である。任意のイベントで、サブルールの括弧は外側のルールにある括弧の数に 影響を及ぼさない。

[Update: Use «$rule» to turn any capturing rule into a non-capturing rule. Or say («$rule») if you only want to capture the string.]

{code} 形式は意味のある値を返さない -- 副作用のためにのみ使用される。任意のクロージャは表明として振舞うことができる。 失敗させるために例外を投げる目的で使われることがあるかもしれない。そのような 例外を投げるにはfail を使うことができる:

    $_ = "666";
    / (\d+) { $1 < 582 or fail }/

任意の表明が付加されたように、この失敗するクロージャはそのクロージャの位置で バックトラックを開始する。この場合、\d+ で バックトラックが発生し、"666" ではなくて "66" に最終的にマッチする。 もしそのようなバックトラックを望まないのであれば、\d+: を代わりに使用する。

しかしながら、これは表明構文のコードを使うのはもっと簡潔である。 括弧で囲まれた Perl の式をアングルブラケットで囲んでやるだけである:

    / (\d+) <( $1 < 582 )> /

I find the parens to be vaguely reminiscent of the parentheses you have to put around conditionals in C (but not Perl (anymore)). Also, the parentheses are meant to remind you that you only want to put an expression there, not a full statement.

裸のクロージャを計算された正規表現を展開しようとするために使ってはいけない。 なぜなら、その結果は無視されるだろうからだ。代わりに、 <{expr}> 形式を使う。 <&rule()> のように、その結果は それが展開されたものではなくてサブルールであるかのように解釈される。

文字列は一般には真であるので、インラインコメントの効果を得るために単に表明する ことができる: <("this is a comment")>。 しかし、このような例を一つの例外を除いては決して使用しない。行を終わらせるコメントは 通常きれいにマッチする(コメント中に現れないので、同一行の最後の正規表現区切り子を 置くことができないことを記憶しておくこと)。{'...'} 構造をコメントに使うこともできる。しかし、これは "useless use of a string in void context" (void コンテキストに置ける無用な文字列の使用) という警告が出るリスクがある。

[...] は新たなキャプチャしないブラケット表記 である。これは次のような目的のためにはうまくいっているようである -- わたしは 別のブラケットを試し、そしてそれらはスクウェアブラケットより早く"見失って"しまうという 傾向があった。そのため我々は (...)<...> を開きと閉じの間の距離がスクウェアブラケットやカーリーブレースよりも短くなる 傾向のある構造のために予約した。スクウェアブラケットはまた、垂直バーを使って 垂直に列挙したときにも都合よく働く。以下はPerl6Grammarクラスの名前つきルールの宣言である (奇妙なメソッド宣言のように見えることに注意)。

    rule state  { <label>
                    [ <control>          {.control}
                    | <sideff> <eostate> {.sideff}
                    | <@other_statements>
                    ]
                };

Huffman符号化はまれな形式は長くあるべきだと主張していて、それは先読み表明や後読み表明 <before ...> および <after ...> のケースに当てはまる(これの否定形は一般的な <!...> ルールの形式を取る)。 これらの prepositions が 操作ではなく表明として解釈されることに注意すること。 たとえば、 <before X> は "X のために我々のいる場所の前を見る"と読むのではなく、"X の前にいることを表明する"と読む。

新しい演算子 :(?>...) 構造を置き換える。この演算子は * がそうであるように その直前にあるものを修飾する。そのためこの演算子は先行するアトム(もしくは量指定された アトム)がブラケットで囲まれた構造であれば自然にスコーピングする。これを トークンの解析をコミットするときはいつでもこれを使うだろうし、アトムを通して バックトラッキングをする場所がないことを正規表現エンジンに伝えるためにも使うだろう。 だから、バックトラッキングはアトム全体を後ろ向きにスキップし、より前にある分岐点で 処理を続けるだろう。以下の例は "b" が後続するのを見つけるために "a"の並びを見つけなければならないときに 長い時間を要して失敗する:

    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaac" =~ /^ a* b /

しかし我々はすでに最も長いものだけがマッチする可能性があるということを知っている。 であるから、コロンを追加してやれば* が すべてを捕捉してバックトラッキングには何も渡さないので1パスで失敗する。

    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaac" =~ /^ a*: b /

You can use colon on a longer sequence too. The following might match a list of expressions separated by comma:

    / <expr> [ , <expr> ]*: /

: を バックトラッキングをしない任意のアトムに対して使うとエラーになる。 これは次の例のようにリテラルのコロンをバックスラッシュでエスケープし忘れたエラーを 捕捉するのに便利だろう:

    /^From: (.*)/

Perl 6では、Perl 5にあった(?(cond)yes|no) のような特殊な制御構造は必要ではない。 なぜならこれはちょっとした微調整があって、通常の選択が同じことをできるからである。 そのような微調整は我々の次のバックトラッキング修飾子であり、 :: 演算子である。これはバックトラックを行うならば 選択のカレントリストのすべてで失敗する。次のような選択のリストを考えてみよう:

    [ <A> <X> | <B> <Y> | <C> <Z> ]

バックトラッキングが働くルールは、もし <A> もしくは <X> のいずれかが失敗したならば次の選択肢へとバックトラックする というものである。<B><Y> についても同様である。 <C><E> の場合には次の選択肢がないので、構造全体が失敗する ことになる。これはどのように条件が働くかではなくて、条件のみが 実行されるものを決定する。特定のケースをコミットしたならば、それは 条件がそこに存在しなかったかのように成立するか失敗するかしなければならない。 このため我々の目的とするところで必要となることのすべては表明を区切る何かを 持つということである。これは :: が行っていることで、 "then" (それから)もしくは "corresponds to"(対応する) のように読む。次のように書いたならば

    [ <A> :: <X>
    | <B> :: <Y>
    | <C> :: <Z>
    ]

<A>, <B>, もしくは <C> の失敗は(もしあれば)次のケースへ前進するのに対し、 <X>, <Y>, もしくは <Z> の何らかの失敗は 選択リストの前の部分へバックトラックを引き起こし、前者の選択を修正する (<X>, <Y>, <Z> の成功が"フォワードトラック" (forward track)を引き起こして選択リストの後ろへ進み もっとマッチするように挑戦するのと同じように)。これはすでに存在する正規表現 セマンティクスに対する自然な写像である。以下に挙げるのはPerl 6からのより現実的な例である。 これは文修飾子(statement modifiers)を解析する(<ws> ルールは省略可能な空白を解析する)。

    rule modifier { if     <ws> :: <expr> { .new_cond(0,$expr) }
                  | unless <ws> :: <expr> { .new_cond(1,$expr) }
                  | while  <ws> :: <expr> { .new_loop(0,$expr) }
                  | until  <ws> :: <expr> { .new_loop(1,$expr) }
                  | for    <ws> :: <expr> { .new_for($expr)   }
                  | <@other_modifiers>  # ユーザー定義
                  | <null>              # 修飾子なし
                  }

それぞれのケースで、キーワード(とそれに続く空白)を認識し、式を探す必要があり、 その後で構文木を構築するクロージャを呼び出す。いずれでも失敗した場合には、 修飾子ルール全体が失敗する。 :: の前にある表明の失敗を 最後の二つの選択肢でのみ得ることができる。

:: が"そこから"バックトラックできないという ことだけを述べていることに注意すること。全体としてバックトラックする別のリストに ついて何も述べてはいない。そのような選択肢は場所を選ぶので、正規表現エンジンは 別のリストにバックトラックすることと別の選択肢を試すことを許可する (これを禁止するには、選択リストの閉じ括弧の直後に : を置いてやる)。

::: 演算子は Perl 5には対応するものはなく、 :: のように振舞う。バックトラッキングが これをまたいだ場合、カレントのルール定義においてすべての選択肢で失敗する(この定義を 実行する任意のルールがなかった場合も)。つまり、 /.../, m/.../, s/...//, rx/.../, rule {...} といったレキシカルなenclosingのすべてで失敗する ということである。ネストした<...>, [...], (...) はスキップする(クロージャの中でネストしたパターンはそれ自身のルールであるように 取り扱われるが、{...} クロージャを渡すチャンスを 得ることは決してない)。

最後の例に合った選択は正規表現のトップレベルのものであったので、 ::: 演算子を :: と同じ効果を得るものとして使うことが できた。なぜならこれはルールを終端し、あの場合に選択を終端するものであるからである。 これらすべてを Prolog の "カット" オペレータとの一種として考えることができる。

:::: 演算子を飛び越えてバックトラックするならば、 それはあなたのプログラムをディスクから消し去るであろう ;-)(訳注: 良く分かりません・・・)

実際、本当の:::: 演算子の本当の名前は <commit> である。これは バックトラックが起きたときにカレントルールのみでなくマッチ全体を失敗させる。 つまり、カレントの文字列で実行されている動的な /.../, m/.../, s/...//, rx/.../, rule {...} のエンクロージングの最も外側の すべてで失敗するということである。

<commit> を飛び越える "カット" オペレータがある。これは適切な名前 <cut> がついている。これには二つの 理由がある。まず第一に、それを飛び越えてバックトラック使用とするときに これは本当のカットオペレータであり、カレントマッチを <commit> のように完全に失敗させる。 しかし、別の理由で副作用がある。それは <cut> が現在マッチングを行っている 文字列の前部を切り飛ばし、カレント位置を文字列の新しい先頭にするというものである。 無限長の文字列にマッチングする可能性があるのなら、これはすでにコミットした マッチ部分を捨て去る方法があるという点において重要である。Perl 5 では、 s/^pat// 操作のコーディネイトされたシステムを 使ったものしかなかった。しかし <cut> 表明を使うことにより、普通にマッチさせることができ、かつ "受理" 状態に到達したときに トップレベルのルールの中で一つの場所をカットすることが可能となる。

idle speculation の領域において、我々は 明らかに冗長な s/// を与える <cut> の変種を定義することができる:

    s/foo/bar/;
    m/foo <replace("bar")> /

クロージャの中の"失敗"のスコープを制御するのに特殊な形式は必要ないことに注意。 適切なバックトラッキング演算子をクロージャの前に置くだけである:

    / pattern ::: { code() or fail } /  # ルール全体が失敗する

キャラクタクラスの再構成

前述したように、キャラクタクラスはより標準的な文法ルールになった。これは "キャラクタ"の定義が曖昧なものになったからである。それは 列挙されたキャラクタのクラスを降格させる動機の一部であり、別の目的のために スクウェアブラケットを拝借した理由である。実際、昔のよしみで スクウェアブラケットを列挙されたキャラクタのクラスとして使うときには、 それを囲むアングルブラケットが必要となる。しかしこれは実際には 任意の名前つきキャラクタクラスやUnicodeプロパティ、特にそれらを組み合わせて 使いたいときにはキーストロークを節約する傾向がある:

    旧                  新
    ---                 ---
    [a-z]               <[a-z]>
    [[:alpha:]]         <alpha>
    [^[:alpha:]]        <-alpha>
    [[:alpha:][:digit]] <<alpha><digit>>

外側の <...> はまた、自然に 我々が取り扱うキャラクタセットを定義する任意の拡張構文のコンテナとして振舞う:

    <[_]+<alpha>+<digit>-<Swedish>>

[Update: If the first thing in angle brackets is another angle bracket, you have to put a + between to avoid confusion with "Texas" quotes emulating French quotes.]

State

[このセクションは難解である。あなたの目がなめらか(?)なら良いのだが (This section gets pretty abstruse. It's okay if your eyes glaze over)。]

すべての正規表現マッチはそれぞれ状態オブジェクトを持ち、正規表現の中の クロージャは実際にはオブジェクトのメソッドでそのクロージャのトピックは カレントの状態オブジェクトである。カレントトピックにおいて、単項のドットは メソッド呼び出しとなったので、以下は状態オブジェクトの中で任意のメソッドを 呼び出すことができるという例である:

    /(.*) { print .pos }/       # カレント位置を出力する

状態オブジェクトは文法クラスのインスタンスであっても良い。文法オブジェクトは どのように構文解析木を構築するかを知る付加メソッドを持つ。そのルールは また、ほかのルールや関連する文法のルールを知っている。

クロージャの中の $_ はこの状態オブジェクトを 参照しているのであって、オリジナルの検索文字列を参照しているのではないということに 注意すること。しかしながら、状態オブジェクト上で検索を行ったならば、 オリジナルの文字列上で検索を続ける振りをするだろう。内部検索が成功したならば、 外部状態(external state)の位置は 内部検索が外側の正規表現から直接起動されたルールであるかのように 更新される。

状態オブジェクトは解析木がどのように構築されるかを考慮するので、 バックトラッキングが発生したときにはそのオブジェクトはエラーと推測された 解析木の一部を破棄することができる。文法のアクションメソッドは正規表現の状態の 制御を持っているので、正規表現中の名前つきフィールドにメソッド呼び出しのための 陽な受け渡しなしにアクセスすることが可能である。

たとえば、すでに $expr の 解析木を構築するためのような受け渡しの例を挙げたが、そのメソッドは 実際にはそれ自身を解決することができる。 そのため次のように記述することができる:

    rule modifier { if     <ws> :: <expr> { .new_cond(0) }
                  | unless <ws> :: <expr> { .new_cond(1) }
                  | while  <ws> :: <expr> { .new_loop(0) }
                  | until  <ws> :: <expr> { .new_loop(1) }
                  | for    <ws> :: <expr> { .new_for }
                  | <@other_modifiers>  # ユーザー定義
                  | <null>              # 修飾子なし
                  },

@other_modifiers については後述する 可変スコーピングを参照のこと。

クロージャの中では、$_ はカレントの正規表現の カレント状態を表していて、拡張によりすべての正規表現のカレント状態は カレントマッチに関与している(状態オブジェクトの型はカレントの文法クラスで、 カレントの文法が名前をもっていないものの場合には無名型の可能性がある。正規表現が 文法のメンバーでない場合、RULEの型となる)。カレントの正規表現の状態の一部は 構築される解析木のカレントノードである。カレントの正規表現が成功したとき、その 状態オブジェクトは結果オブジェクトとなり、正規表現の呼び出し元へと返される。 正規表現の呼び出しは返されたオブジェクトを"仮定の"(hypothetical)変数として参照し、 その名前はルールの名前によって暗黙裡に生成されるか、あるいは := をつかって陽に束縛されているかしている。 そのような変数を通してサブルールによりキャプチャされたものを得ることができる (つまり$expr が以前やっていたことである)。

[Update: Only rules of the form <ident> are captured by default. You can use := to force capture of anything else, or the :keepall adverb to capture everything else.]

マッチ全体が成功したとき、トップレベルのノードは結果オブジェクトを返す。 この結果オブジェクトはboolean、数値、文字列といった様々なコンテキストの 様々な値を持つ。結果オブジェクトの名前は $0 である。結果オブジェクトは$1, $2 などの他の情報をすべてもっている。 Perl 5における $& とは異なり、 $0 それを囲むブロックに対してレキシカルに スコーピングされる。拡張により、$1 なども レキシカルにスコーピングされる。

[Update: The $0 variable's functionality is now split up into a $/ variable that represents the match state object, and a $0 variable that represents the capture of the entire pattern. In other words, $0 is exactly like a $1 capture, only with assumed parens around the entire pattern.]

イテレータの一種として、変数に格納されている正規表現はリストコンテキストで 展開されることは、アングルブラケットで囲むかm// とともに使うかしない限り行われない:

    $rx = /(xxx)/;
    print 1,2,<$rx($_)>;
    print 1,2,</(xxx)/>;
    my &rx := /(xxx)/;
    print 1,2,<rx($_)>;

$0, $1 などはこのようなイテレートされたケースではセットされない。 各リストアイテムは結果オブジェクトであり、その内部値を得ることはできる。

Hypothetical Variables, er Values

正規表現中で決定される値は通常、バックトラッキングが発生したときに破棄できるように speculativeに見られるべきである。これは正規表現中で(...) によってキャプチャされた値だけでなく、正規表現中に 埋め込まれたクロージャによって決定される値にも適用される。これらの値のスコープは 通常の変数と比較するといささか奇妙である。これらは動的にスコーピングされるが、 temp 変数とは違う。一時変数はカレントブロックの 末尾でリストアされる。hypothetical 変数はその値をカレントブロックを出た後でも 保持していて、正規表現が成功した場合にその自然な生涯を終わらせるためにクリアされる までそれは続く(ここで自然な生涯とはその宣言した場所に依存する)。 しかし、hypothetical 変数をセットした場所をまたいだバックトラッキングが失敗した 場合には、以前の状態にリストアされる。Perl 5はこの動作をサポートするのに local 演算子を強制していたが、それは間違いだった・ Perl 6では temp が首尾一貫したセマンティクスを 保持し、カレントブロックから抜け出すときに値をリストアする。新たな単語 let は変数に hypothetical な値をセットすることを 指示する(わたしは一時的に "suppose"を使っていたが、"let"の方が短くてすむ)。

    my $x;
    / (\S*) { let $x = .pos } \s* foo /

このパターンを抜けた後で、$x には $1 の最終位置がセットされる。ただし このパターンが成功したときのみ。もし失敗したら、$x にはこのクロージャの終端で undef がリストアされる。 正規表現エンジンがどうバックトラックするか分からないクロージャの中で何かを 行うことは可能である。もちろん、hypothetical な値はそのカテゴリに入らない。 失敗を行うことをこのカテゴリに押し込めるには、 UNDO のような BACK ブロックを定義する必要があるだろう。しかし、 バックトラッキングに注目している。

hypothetical な値の宣言について言及することがあるだろうが、 temp についてそうであるように 我々は変数それ自身を宣言することはないがその新しい値の動的スコープについては そうではない。Perl 6では、次のような記述ができる:

    my $x = 0;
    ...
    {
        temp $x = 1;    # レキシカル変数をtemporizes する
        ...
    }
    # $x は0にリストアされる

(これは基本的にファイルスコープレキシカルの動的スコーピングの便利である。 ファイルの外で可視になることはないのでパッケージ変数をtemporizeするのがより 安全になる)

hypothetical 変数を宣言することができるのはそのトピックが正規表現状態である ときのみである。これは思ったほどの苦難ではない。クロージャが何か別の ルーチンを呼び出して、その引数として $rx_state という 正規表現の状態を渡したとしよう。そうするには次のようにする:

    given $rx_state { let $x = .pos }

[Update: This restriction is no longer in effect. Any variable may be treated hypothetically, not just variables stored in $/. The capture variables in $/ are now syntactically distinguished from ordinary variables. Hypotheticality is orthogonal to that, except insofar as $/ is somewhat hypothetical as a whole.]

$1 などはすべて単純な hypothetical 変数である。 "hypothetical 変数" と言ったとき、その変数がどこで値を格納されたかではなく その内容を動的にどのように扱うかに言及している。ある正規表現が my もしくは our で宣言された hypothetical 変数をセットし、それから レキシカル変数かパッケージ変数を変更する。このとき let は純粋に実行時オペレーションである。

その一方で、その変数があらかじめ宣言されたものでなければ正規表現状態オブジェクトで 格納される。この場合、let も同様に その実行時アクションに加えて正規表現の残りの部分のレキシカルなスコープとして 変数を宣言する。そのような変数は正規表現の外側では直接に見ることができないが、 $0 オブジェクト(常にマッチが成功したと仮定している) を通じて値を得ることができる。正規表現変数が$maybe という名前であった場合、その外部名は$0._var_{'maybe'} である。$0 オブジェクトはハッシュとして 扱うことともできるので、$0{maybe} は短くした表記である。

[Update: Nowadays the short name of that variable is $<maybe>. And the match variable is named $/ instead of $0.]

その他のすべての変数名はそのsigilとともに格納されている。このため、 @maybe の外部名は $0{'@maybe'}であり、 %maybe の外部名は $0{'%maybe'}である。

[Update: None of these are stored with their sigil, which means you can't store two different types under the same name unless you explicitly bind to a name like $<@maybe>.]

$1 は特殊なケースである -- これは それがあらかじめ定義されていないものであるのに正規表現の外側で可視である。 しかし、Perl は番号づけされた変数 $1 を $0 オブジェクトの部分配列として格納することをすでに知っている: $0[1]。番号付けされた変数は配列を 通してのみ使うことができ、ハッシュではできない。

[Update: the number variables are also available through the hash, so $1 is the same as either $/<1> or $/[0].]

$0 は現在実行されている正規表現の 状態を表すので、ルールの中で完全なサブルールの結果として使うことはできない。 <somerule> という名前のサブルールが 成功したとき、正規表現の状態は自動的に $somerule という名前のついた hypothetical 変数に自動的に格納される(間接的にアクセスされたルールは 陽にキャプチャしなければならない。そうしなければ値を取り出すための 名前をもつことができない。次のセクションでより詳しく述べる)。

[Update: Any subrule's capture may be suppressed with French quotes.]

カレントの再帰的正規表現実行のように、すべてのキャプチャされた hypothetical 変数 を表すハッシュの木が自動的に構築される。このため、正規表現の外側から、 $0{somerule}[1] のようにして サブルール <somerule>$1 を取り出すことができる。

[Update: These days that's $/{'somerule'}[0] or $<somerule><1>.]

名前つきキャプチャ

hypothetical 変数をキャプチャするための名前に束縛したいと考えたとしよう:

    / (\S+) { let $x := $1 } /

短くするとこうなる:

    / $x:=(\S+) /

括弧は名前とは独立に番号付けされる。このため、 $x$1 の別名である。

適切に量指定されたパターンをキャプチャするために配列を使うことができる:

    / @x := (\S+ \s*)* /                # 空白を含む
    / @x := [ (\S+) \s* ]* /            # 空白を含まない
    / @x := [ (\S+) (\s*) ]* /          # 各要素は[word, space]

一般的に、スクウェアブラケットに名前を付けることが(スクウェアブラケットに) キャプチャさせるようにすることはなく、その中にある括弧に対する定義を 与えるのだということに注意すること。 括弧とルールだけがキャプチャ可能である。内側にあるものをキャプチャしない スクウェアブラケットに名前を付けることはイリーガルである。

ハッシュにキャプチャすることもできる:

    / %x := [ (\S+)\: \s* (.*) ]* /     # キー/値 のペア

マッチの後で、$1 はキーのリストを返し、 $2 は値のリストを返す。キーだけを キャプチャできる:

    / %x := [ (\S+) \s* ]* /            # キーだけ入力、値は undef

クロージャの戻り値もまたキャプチャすることができる:

    / $x := { "I'm in scalar context" } /
    / @x := { "I", "am", "in", "list", "context" } /
    / %x := { "I" => "am in hash context" } /

これらの例で括弧を使っていないことに注意。 次のように記述した場合:

    / $x := ({ code }) /

クロージャによって探索されたテキストをすべてキャプチャするが、クロージャの 実際の戻り値は無視される。

numeric 変数を使って名前付けすることにより括弧グループの再順序付けを 行うことができる:

    / $2:=(.*?), \h* $1:=(.*) /

numeric 変数を使ったならば、numeric 変数はその場所から番号付けをやり直す。 このため、後続するキャプチャは知られた番号であってよい (先行する番号から連想される)。そのため、次のようにして各選択肢の 番号をリセットすることができる:

    / $1 := (.*?) (\:)  (.*) { process $1, $2, $3 }
    | $1 := (.*?) (=\>) (.*) { process $1, $2, $3 }
    | $1 := (.*?) (-\>) (.*) { process $1, $2, $3 }
    /

キャプチャをカレント位置に依存するものとして参照することもできる。 $-1 は直前のキャプチャ として参照する (すでに知られている$+と同様に)。 $-2 は二つ前のものを参照する。 $-3 以上のものを使おうとしたなら 我々がそこに急行してあなたを insane asylum に連れ去るだろう。

<rule> を通じて呼び出された サブルールもまたその結果をhypothetical 変数にキャプチャする。 任意の <...> の結果を命名することが できるが、文法ルールはすでにデフォルトで名前をもっている。このため、同じルールを 二度以上呼び出すことがない限り名前を与える必要はない。だから、 "key" と "value" の文法を持っていたとすると、次のように書ける:

    / <key> \: <value> { let %hash{$key} = $value } /

[Update: That is now written:

    / <key> \: <value> { let %hash{$<key>} = $<value> } /

]

もちろん、典型的な文法では典型的なルールは文字列を返さないが、 無名オブジェクトへの参照は解析木のノードを表す。しかし、これは サブルールがキャプチャする決定に依存する。サブルールでキャプチャされた ものが単一の文字列であったときにのみ、これは得られる(何もキャプチャしなければ マッチ全体を得る)。

複数のアイテムをキャプチャする任意のキャプチャは、スカラー変数への代入が行われて いれば、無名のリストを自動的に生成する。これはキャプチャするか否かの 量指定の検査によって明確になるので、驚くことはほとんどないだろう。 従って、次のように記述すると:

    / $x := <word>*/
    / $x := <word>+/
    / $x := <word><1,3>/

[Update: That last should use **{1..3} instead.]

名前付けを "pluralize" し、無名リストとして $x の中の値の幾つかの番号を期待することができる。しかしながら、 ? 量指定子は特に pluraize することはない。 次のように記述した場合:

    / $x := <word>?/

$x はそのサブルールの結果か undefのいずれかになる。

ゼロ幅の表明の結果に名前を付けることができるが、空文字列を得る結果にしかならない だろう。それでもこれは表明が失敗したときに未定義値を得ることになるので 便利だろう(ゼロ幅の表明から返されたゼロ幅の文字列を陽にキャプチャすることが可能)。

可変スコーピング(Variable Scoping)

変数 @foo を正規表現の中の右辺値として 参照したとき、以下に挙げる場所で存在する変数として検索される:

1. まず始めにmy @foo もしくは our @foo によってすでに宣言されている変数かどうか確認する。 もし宣言されていたらこれで終わり。

2. 次にカレントの正規表現の名前テーブルで @foo を探す。この変数の名前は実際には $0{'@foo'} である。

[Update: These $/ variables now have names like @<foo>, so skip this step.]

3. 正規表現がある文法に属しているならば、続いてその文法オブジェクトで @foo を探す。もしあれば、その真の名前は @.foo もしくはそれに類したものである (正規表現がコンパイルされたときに文法オブジェクトがまだ構築されていないことに 反対するかもしれない。すべてが終わった後で、その正規表現は文法オブジェクトの コンストラクタに渡されるだろう。しかしそのような変数がオブジェクトの属性として 宣言されていたならば、構築が終わったときにそういった変数/アクセサが存在する だろうことを知っている。そして、それは正規表現をどのようにコンパイルするかの 情報には十分だろう)。

[Update: I think we can skip this one too--just import the array if you need it, or call it via a real rule accessor.]

4. 続いて宣言されたコアのグローバル変数 @*foo として @foo を検索する。

5. 最後に、"strict vars" が有効になっていなければ、@foo がカレントのパッケージに格納されていると 仮定する。ここまでやって見つからなければ stricture error (制限エラー?)である。

Variable Interpretation

すでに述べたように、裸のスカラーはその内容にリテラル的にマッチする ($var で定義されている正規表現にマッチ させるには<$var> を使う)。 添え字付けされた配列とハッシュはそれがスライスとして添え字付けされていない限り スカラーの様に振舞う。

裸の配列(添え字付けされていない)を使った場合、それはその配列にその場所でリテラル的に マッチする任意の要素にマッチする(配列やハッシュのスライスも同様に振舞う)。 次のようにすると

    @array = ("^", "$", ".");
    / @array /

これは以下のように書いたのと同じである

    / \^ | \$ | \. /

しかし次のようにスライスを書いた場合には:

    / @array[0..1] /

ドットにはマッチしない。

配列を正規表現の選択の要素として扱いたい場合には以下のようにアングルブラケットで 囲んでやる:

    @array = ("^foo$", "^bar$", "^baz$");
    / <@array> /

正規表現中の裸のハッシュは洗練された match-via-lookup (ルックアップを通じたマッチ?) 機構を提供する。裸のハッシュは以下のようにマッチを行う:

1. 文字列のカレント位置で キーにマッチする。

1a. ハッシュが一部の正規表現に対し keymatch 属性セットを持っていたならば、その正規表現をキーにマッチさせるために使用する。

そうでなければ、キーにマッチさせるために /\w+:/ を使う。

2. もし文字列のカレント位置でキーが見つからなければ、マッチは失敗する。

3. そうでなければ、マッチしたキーに対応するハッシュ中の値を取り出す。

4. そのようなキーが見つからなければマッチは失敗する。

5. ハッシュが valuematch 属性を持っていなければ マッチは即座に成功する。

6. もしあれば、そのハッシュの valuematch 属性 を文字列のカレント位置の値を展開するために使用する。

7. 展開できる値がなければ、ハッシュのマッチングは失敗する。

8. 展開された値文字列がハッシュのキーの実際の値と eq であれば、オリジナルハッシュのマッチングは 即座に成功する。

9. そうでなければ、オリジナルハッシュのマッチングは失敗する

従って、裸のハッシュのマッチングは以下に等しい:

    rule {
        $key := <{ %hash.prop{keymatch} // /\w+:/ }>    # find key
        <( exists %hash{$key} )>                        # if exists
        [ <( not defined %hash.prop{valuematch} )> ::   # done?
            <null>                                      # succeed
        |                                               # else
            $val := <%hash.prop{valuematch}>            # find value
                <( $val eq %hash{$val} )>               # assert eq
        ]
    }

典型的な valuematch は以下のようなものだろう:

    rule {
        \s* =\> \s*          # => にマッチ
        $q:=(<["']>)      # クォートのはじめにマッチ
        $0:=( [ \\. | . ]*? )   # マッチした値を返す
        $q                      # 後続のクォートにマッチ
    }

一言で言うと、 valuematch 属性のあるなしは そのハッシュがキーのみにマッチするようにするか、キーと値の両方にマッチする ようにするかを制御する。

[Update: The above is all completely bogus. A hash's set of keys are simply compiled into a longest-first token match table. The corresponding value contains the closure or rule to fire off when you match, or a boolean to make the key match merely succeed. See S5.]

ハッシュはアングルブラケットの内側で使うこともできる。その場合、同じ手順 (前述のステップ1とステップ2)によってキーを見つけ出すが、対応するハッシュの値を 常に正規表現として取り扱う(ハッシュが持っているかもしれない属性には関係しない)。 解析はそれからハッシュの中で見つかったルールに従う。たとえば次のようにして 制御構造の集合を解析することができる:

    rule { <%controls> }

ハッシュ %controls は "if" や "while" のようなキーを持つことができる。対応するエントリーは if 文や while 文の残りの部分をどのように解析するかに言及している。 たとえば:

        %controls = ( 
            if     => / <condition>      <closure> /,
            unless => / <condition>      <closure> /,
            while  => / <condition>      <closure> /,
            until  => / <condition>      <closure> /,
            for    => / <list_expr>      <closure> /,
            loop   => / <loop_controls>? <closure> /,
        );

この場合次のように書くと:

    <%controls>

次のように書いたのと同じマッチを行う:

    [ if     \b <%controls{if}>
    | unless \b <%controls{unless}> 
    | while  \b <%controls{while}>
    | until  \b <%controls{until}> 
    | for    \b <%controls{for}> 
    | loop   \b <%controls{loop}>
    ]

Only it actually works more like

    / $k=<{ %controls.prop{keymatch} // /\w+:/ }> <%controls{$k}> /

[Update: This is also bogus. The keys are treated as a set of rules with longest-first semantics for any leading literal components. See S5.]

Perl 6ではスラッシュによって区切られた正規表現に埋め込まれた式の中で // を使うことは完全に合法であるということに注意。 これは正規表現がもはや文字列としては扱われないためで、このため解析する前に その終端を見つける必要がない。1パスで解析することができるので、式の解析器は 外側のスラッシュに関して心配することなく // を取り扱うことができる。そして、 最後のスラッシュは式解析器が見たものに関して煩わされることなく 正規表現解析器によって終端として認識される。

裸のサブルーチン呼び出しを正規表現の中で使うことが可能である。 そのとき & を前置してやり、引数を括弧で囲む。 そのサブルーチンの戻り値はリテラル的にマッチする。サブルーチンには副作用があっても よく、失敗するために例外を投げても良い。

Defining Your Own Rules

あなたの名前が Hugo であると仮定し、表明の否定のために ! を使うのが好ましくなかったとしよう。 あなた自身の表明を以下のようにして定義することができる:

    my rule not (str $rx) { <!<{"<$rx>"}>> }            # Hugo の not を定義する
    / <not [a-z]> /     # <![a-z]>に同じ

このルールは my が使われているので レキシカルなスコープである。これが sub の宣言と似ていると感じたなら、それは正しい。事実、クロージャのように 無名で宣言することすら可能である:

    my $not = rule (str $rx) { <!<{"<$rx>"}>> };
    / <$not tonight dear> /

しかし、一般的に使用するための文法を書いているためにレキシカルスコープを好まない かもしれない:

    grammar HugoGrammar {
         rule not ($rx) { <!$rx> }
         rule identifier { <not before \d> \w+ }
         rule \j { \c[LF] }
         rule parse { ^ <identifier> \j $ }
    }
    HugoGrammar.parse($line);

この場合ルールは単に文法クラスのメソッドであり、文法クラスは 普遍的な RULE 文法クラスから暗黙か明示であるかを問わず派生した任意のクラスである。 <before \w> のような組み込みの正規表現の表明は 実際には RULE クラスのメソッドを呼び出しているだけである。 文法の名前空間は単にカレントクラスのメソッド名前空間である。そしてそれは クラスのメソッドに加えすべての継承されたメソッドがある。

[Update: Nowadays it's the Rule class.]

通常のサブルールに加え、次のような妙なメソッド名が許される:

    rule :a { ... }
    rule \a { ... }

[Update: These are now handled as macro-like syntactic categories. See S5.]

Perl の文法をその場で変更するモジュールは、デフォルトの Perl6Grammar から 派生した無名文法クラスによって可能である。カレントの正規表現の状態は レキシカルスコープの残りの部分について新しいルール集合を使って解析を続行する。 連続した文法的変化は、陽に異なる文法に切り替えない限り カレントの無名文法から派生するだろう。

メソッドが存在するかのように文法を書いたので、仮引数リストやコンパイル時属性も含めて メソッド宣言の完全な構文にアクセスしている。このため、 厳密に再帰下降構文解析器を書きたくないような場合に 演算子の優先順位のような現実的な情報を使って容易にルールに注釈できるのである (我々はPerlのためにそれを望まない)。

受理されたRFC

RFC 072: 可変長のlookbehind。

これは私にとって良いことのようだ。これは構文木中のノードの順番を逆にするための 単なる SMOP(Simple (or Small) Matter of Programming) であり、木を逆にすることが 不可能なときにより良く決定することができると私は考えている。逆順の構文木の 操作は全体的に透明なものではなく、このため量指定子が実際には左から右ではなく 右から左へ働くということをドキュメント化する必要があるだろう(逆順で認識する ことができないような多くの構文構造についてドキュメント化を行うのも良い考えだろう)。

後読みの構文は以下のような表明構文を使う:

    <after ...>         # 肯定後読み
    <!after ...>        # 否定後読み

pos() 関数がリストコンテキストにおいて複数の 値を返す可能性がある。しかし、それらの位置がどこであるかを知るための独立した キャプチャされた要素はよりリーズナブルであると私は考える。 pos 関数は実際には、最後に成功した マッチからの正規表現結果オブジェクト中にあるより一般的なデータ構造の特殊なケースに 過ぎない。この場合、pos よりももっと良い名前を つける必要があるだろう。多分 $0 かなにか。 そうして、$0.beg$0.end, $1.beg$1.end などのように得る。@$0 はキャプチャしたもののリストを返すので、 始端と終端のリストが欲しければ @$0^.beg@$0^.end を行うことができる。 魔法の配列 @+@- はなくなってしまうということは言ったかな? Never could remember which one was which anyway...

[Update: $0 still represents the entire matched string, but the match object is now $/, and a list of all beginnings is returned by the hyperoperator $/».beg. But note that string positions are not necessarily integers in Perl 6. They are tagged with the units of the string, so that you can't inadvertently mix byte, codepoint, or grapheme offsets.]

RFC 093: Regex: インクリメンタルなパターンマッチングのサポート

この提案が十分強力であるとは考えていない。"無限"文字列はより強力な コンセプトである。しかし、無限文字列もまた十分強力ではない!

ジェネレータによって定義されるmissing 要素のための"無限"配列を持とうとしている (そのアクションは別のソースからデータをもっと読み出すくらい簡単にできる)。 同じことを文字列に対しても直接できるか、(文字列もしくはstringifiable オブジェクト) の配列を通して実装される文字列を定義することができる。そしてこの方法で 無限を達成する。後者のアプローチは配列要素の境界が、 ストリームの中のトークン中のトークンの間のゼロ幅の境界として意味を成す効果がある。 <,> がそのような境界にマッチできると 考えている。

そのような文字列としての配列は、 抽象文字列がオブジェクトのリストから構築されていたり属性を持った文字列の リストであった場合にはトークンとともに隠されたメタキャラクタを連想させることを許す。 これは典型的には構文解析器がレキシカルアナライザからのデータをどのように受け取るか ということである。オブジェクトのリニアなストリームをオブジェクトの解析木に変換する のは構文解析の仕事である。

境界やメタデータに対するマッチングは、正規表現エンジンが配列に対するマッチングで あることを認識するか、文字列のエミュレーションが抽象文字列を配列にすることを 通して可視にできるかしない限り可能ではない。後者は @array =~ /regex/ が現在のところ 配列の独立した各要素に対するマッチングとして解釈されていて、 実際は配列である文字列の他の使用法があるのでので好ましいだろう (Apocalypse 4で議論した=~ マトリックス ルールによる)。事実、@array =~ /regex/ は 無限文字列の集合に対する平行したマッチングとして考えることができるが、 ちょっと恐ろしいようだ。

[Update: The =~ operator is renamed ~~, and it doesn't automatically "any-fy" an array anymore, so we could pretty easily make it work over an entire array as if it were a string.]

配列要素の間の強化について何の考慮をしなくとも、このアプローチはファイルを 塊で読み出すことができる能力を与え、 境界をなめるのでパターンがマッチしないことを心配することはない。

メモリーに文字列や配列全体が入ることを約束しないような 無限文字列や無限配列よりもサブルーチンに対してマッチングをするという反論が あるかもしれない。しかしこれは実際には主眼点ではない。なぜなら一般的には ある正規表現は文字列の始めへバックトラックする可能性があるからである。 そして、無限文字列や無限配列の前部を表す手段がない。文字列や配列の 先頭に戻るかどうかはプログラマーに依存していて、 プログラマーが substrsplice のような演算子や、新しい<cut> 表明を 使って管理するよりも より直感的な方法があるとはわたしは考えていない。

その代わりに、RFC 316で述べられたcaching 問題を除外する 文字列/配列が実在する。

そのような文字列/配列をどのように宣言するかという疑問が残っている。 magical 名の確認をすることを決めたとすると、次のように宣言できる

    my $@array;

$array@array は同じオブジェクトを参照するが、 $array としたときは文字列として扱われ、 @array) としたときは配列として 扱われる。入力ルーチンのセットアップは次のようにする

    my $@array is from { <$input> };

付加的な行(もしくは塊(chunks))は<$input> イテレータからくる。

p しかし実際、配列の無限の性質はオブジェクトの影響下にあり、変数ではない。 けっきょくのところ、通常の配列に対しても次のように書けるようにしたい

    @array := 1..Inf;

このため次のようにも書けるが:

    my $@array := <$input>;

しかし別名付けを壊す必要があると私は考える。これはより冗長な消費において 一層のフレキシビリティを我々に与える:

    my @array := <$input>;        # @array はここでイテレータに束縛された
    my $array is ArrayString(@array);   # 通常のtie

これは以下のようなクールで sickな事柄をさせる:

    my @lines := <$article>;
    my $_ is ArrayString(@lines);
    s/^ .*? \n<2,> //;  # $_ と@linesからヘッダを取り除く!
    for @lines { ... }  # 残りの行を処理する

この for ループは無限に繰り返される 可能性がある。なぜなら、@lines は 暗黙裡にイテレータから拡張されているからだ。この配列はその終端で自動的に 拡張されるが、その先頭を自動的にシフトすることはしない。このため、 メモリを使い果たすことなくループを無限に続けたいのであれば、次のように記述する 必要がある:

    substr($_, 0, $_.pos, "");

同じ効果は <cut> による表明を 使った正規表現にも及ぶ可能性がある。これは新しい文字列の先頭にカレントポジションを 移す(<cut> を越えてバックトラックしたら マッチ全体が失敗する)。

[Update: Now we can just say <@lines ~~ s/^.*? \n**{2...} //>.]

RFC 110: counting matches

数値コンテキストで使ったときにパターンにマッチを数えさせれば、何のオプションも 使わないでできるだろうと思っている:

    $count = +/foo/;

もしオプションが必要になったなら、それは多分 :n になるだろう。

RFC 112: 正規表現中の代入

本RFCは基本的には $foo:=(...) 記法で カバーされている。本 RFC はそのような代入がクロージャの前で行われる のを除いて、終わりまで行われないことを主張している。わたしは別の方法で 対処することを主張したい: カレントの hypothetical 束縛はチェックすれば 代入されるが、オプティマイザは見ていないことを決定することができるので、 出現を維持する必要はない。反対に、$foo$1 とすることのfancy なやり方であって、 $foo を保守するオーバーヘッドは $1 よりも少ないだろう。もう一つは 文字列へのオフセットのテーブルを指示するということである。これは hypothetical変数で正しくスコーピングされていることを仮定している。

RFCから幾つか抜粋しよう:

The camel and the docs include this example:

       if (/Time: (..):(..):(..)/) {
            $hours = $1;
            $minutes = $2;
            $seconds = $3;
        }
これは以下のようになった:

      /Time: (?$hours=..):(?$minutes=..):(?$seconds=..)/

現在はこう:

      /Time\: $hours:=(..) \: $minutes:=(..) \: $seconds:=(..)/
任意の代入が、コードがローカライズされる前に呼び出されるようにするので 代入は式が最終的に失敗するときにアンロールすることができるのが適当かもしれない。

ローカライズ(もしくはtemporized)よりは、hypothesizedである。

本 RFC の最初のバージョンでは後方参照を許していなかった。これは欠点であったと 私は考えている。これは (??{quotemeta $foo}) で行うことができるが、私はこれが扱いにくいものであることに気づいた。名前つきの 後方参照のよりよい方法は (?\$foo) だろう。

後方参照は現在hypothetical 変数に一本化された。このため、このことは発生しない。 単に $foo を使う。

[Update: Now $<foo>, short for $/{'foo'}.]

内容を必要とするキャプチャリングのためにこの方法を使うことによって、 通常のブラケットによるキャプチャリングをストップすることを抑止するかもしれない。 そして、 (?:...) を使う必要があるかもしれない。 そこで私は単にグループ化すだけでキャプチャしない ((?:...)の振る舞いのようにする) 通常のブラケット /b (bracket?)を正規表現に追加することを提案する。

/b は、キャプチャしないブラケット [...] があるので必要なくなった。

RFC 144: 空の正規表現の振る舞いを単純にする

賛成する。振る舞いは単純であるべきだ。しかしながら、常にマッチングするよりは 空パターンや選択肢の中の空のものに対してはエラーにすることを提案する。 もしそういったものが必要であるならば陽に <null> を使う(これは $foo/$foo/ の中で空になることは問題にはならない。なぜなら変数は 正規表現エンジンによって管理され、展開されることはないからである)。

RFC 150: マッチしたサブパターンのハッシュを返すための拡張正規表現構文

$foo:=(...) 記法がこれをカバーしている:

    / %hash{foo}:=(...) %hash{bar}:=(...) /

クロージャを使っても同じことができる。

RFC 156: first match function (?...?) をマッチコマンドのフラグに置き換える。

以下のような:f 修飾子があるとよさそうである:

    m:f/.../

しかし split のような解析を行う動詞の 集合を持ってしまうと曖昧になる可能性がある:

    split /.../
    count /.../
    first /.../

これらは実際にはオブジェクト、文字列、正規表現に対する メソッドであるかどうかがはっきりとしない。任意のイベントにおいて、 そうしたことをやるべきであるとは考えていない。わたしは本 RFCの ?...? 構造をなくそうという 基本的な前提は受け入れようと思う。

現在、このオプションは :once のように記述する ようになった。

RFC 165: tr///中での変数を許す

パターンの展開をデフォルトで行うことが間違いであるのなら、スカラーの展開を通じた tr/// のインターフェースは二重の間違いであると わたしは思う。置換の実行時の生成は位置に依存していないマッピングに基づくもので あるべきである。つまり、以下のような長い二つのリストではなくて:

    abc12xyz => ABC34XYZ

以下のように指定する:

    abc => ABC
    12  => 34
    xyz => XYZ

これらはスカラーのペアよりはスカラーのペアのリストのように見える。事実、 内部的には平行した置換のように行われる:

    s:e(/a/A/,
        /b/B/,
        /c/C/,
        /1/3/,
        /2/4/,
        /x/X/,
        /y/Y/,
        /z/Z/)

    $string.tr [ " "     , "<"   , ">"   , "\n"   ],
               [ "&nbsp;", "&lt;", "&gt;", "<br>" ];

あるいは tr(%trans) についてはどうか?

    %upper = {
        "a-z" => "A-Z",
    }
    $string.tr %upper;

上記のようにするか、もしくはペアのリストを使う:

    $string.tr("a-c" => "x-z",
               "1-2" => "3-4",
               "A-C" => "X-Z",
              );
    @trans = [
        "a-z" => "A-Z",
        @tr_danish,
    ];
    $string.tr(@trans)

RFC 166: 選択肢リストとクォーティング

リテラルの選択肢リストは単純に配列によって含まれる:

    /@names/

サブルールの選択肢リストは以下のようにする:

    /<@names>/

変数のマッチはデフォルトでリテラル的に行われるため、クォーティングの必要はなくなった・ サブルールのように文字列の展開を行うにはアングルブラケットを使用する(しかし使用する 正規表現をあらかじめプリコンパイルしておくのが望ましい)。

RFC 191: 賢いcontainer slicing

As proposed, this might prevent us from using a regex object as a key to a hash. However, with some tweaking, it'll fit in with how slicing is done in Perl 6.

Perl 6 はその出現に応じてわたしの思ったように添え字付けを行う。

    %hash{"foo"}

これは単一の添え字を持つ。そして次のようにすると

    %hash{"a" .. "z"}

26 の添え字を持つ。スカラーガイダンスにない場合、添え字はリストコンテキストで 解釈される。このため

    %hash{ @array }

これは自動的に配列中にあるキーのリストのスライスになる。デフォルトでは任意の関数は 複数の値を返すリストコンテキストで呼び出される。Perl 6 の subscripts は スライスの方向にバイアスがかかっている。このバイアスを取り消すために、 以下に挙げるような特殊な解釈をされる subscripts がある:

    %hash{"foo"}        # スカラーリテラル
    %hash{bar}          # スカラーリテラル

[Update: Now %hash<bar> instead.]

    %hash{1}            # スカラーリテラル
    %hash{$x}           # スカラー変数
    %hash{\$x}          # スカラーリファレンス
    %hash{["a", "b"]}   # 配列リファレンス
    %hash{{"a" => "b"}} # ハッシュリファレンス
    %hash{ "a" => "b" } # ペアリファレンス
    %hash{ /pat/ }      # ルールリファレンス
    %hash{ _ expr }     # 単一の文字列を返すようにexprに強制する

[Update: Now ~ instead of _. Also, active slicing with closures is done with a .slice method on either arrays or hashes. Ordinary subscripts always assume integer slices for arrays and string slices for hashes (by default). The optimizer is allowed to assume that in @foo[@bar], the @bar array returns a list of integers.]

    %hash{ + expr }     # 単一の数値を返すようにexprに強制する

ブール式とクロージャは単一の値のように見えるが、添え字の可能な値すべてに対して マッチが行われる。

    %hash{ ?1 }         # すべての添え字を選択する
    %hash{ ?/pat/ }     # patにマッチする添え字を選択する
    %hash{ $_ =~ /pat/ }# patにマッチする添え字を選択する
    %hash{ $_ ge "a" }  # 小文字のキーを選択する (ASCIIを仮定)
    %hash{ .ge "a" }    # たぶん同じこと
    %hash{ { expr } }   # 真を返すクロージャの添え字を選択する

複数のスライスされた添え字はセミコロンで区切られる。このため、リストを構築するために スライスされた添え字のそれぞれにカンマを使うことができる。このことは多次元配列 により重要である:

    my @array is dim(9,9,9) = cubic();
    @3d_slice = @array[ @x; @y; @z ];
    @3d_slice = @array[ 0,1,3,8 ; 0,1,3,8; ?1 ];
    @3d_slice = @array[ 0..9 ; 0..9:-1; ?test($_) ];
    @3d_slice = @array[ !($_ % 2) ; 0..9:3; ?test($_) ];

[Update: dim is now spelled shape. See S9.]

RFC 274: 正規表現に対する一般化した追加

This proposal has significant early/late binding issues. A definition that forces run-time overhead is not as useful as it might be. On the other hand, a pure compile-time mechanism is not as general as it might be--but a compile-time mechanism can always compile in a run-time mechanism if it chooses to defer evaluation.

このため、構文的な warpage のための良い場所のように見える。これはコンパイル時束縛と 実行時束縛の両方を可能にする。<...> という 表記を拡張可能な構文のために使っているので、Perlの構文の特定の部分を解析する 文法ルールは他のPerl 文法のルールを微調整するようにやさしいことである。

文法を、 <word> のインスタンスを定義することが 簡単な正規表現に望みのままに結び付けることができる。 (これらのサブルールは本 RFCが定義するコールバックである)。 これらのサブルールは PerlがコンパイルしているときかPerl が実行されているときかの いずれかに束縛することができる。後者は正規表現やコードリファレンスがそれぞれに くるので効率的である。

(?{...})などのコードがforward マッチの中で評価されたならば、それは バックトラッキングのためにコードが巻き戻されたときに実行されるが、 forward マッチにおいては 無視されるコードブロックをサポートするのに良いアイデアかもしれない。

そう、とはいうもののhypothetical な値がこのためのプレッシャーを取り除く。 しかし、あるクロージャがBACK ブロックを有していたならば、それは自動的に バックトラックにおいてfired off (放す?)するだろう。LAST についても同様。 変数における back 属性を提案する。 ある意味では、

    let $var = $newval

これは以下のようにしたのと同様であるが

    our $var is back { .set($oldval) } = $newval

$var がグローバルなシンボルテーブルではなく 正規表現の状態オブジェクトの中に格納される点が異なる。

RFC 276: qr()中の括弧の数のローカライズ

完全に賛成する。キャプチャをサブルールの外に引き出す問題のために、 それが"返す"ものを決定するサブルールに適している。我々は幾つかのインテリジェントな デフォルトを作ることができるが、異なる種類のルールは異なるデフォルトを 持ちたいと思うかもしれない。一つのやり方として、 結果として返されるような単一のキャプチャがあったならば それに言及するというものがある。キャプチャがなければ、サブパターン全体が キャプチャされたかのようになる。複数のキャプチャがあったならば、それらは 無名リストとして返される。このためサブルールによる $1 は以下のように書ける:

    / $sub:=<subrule> { print $sub[1] } /

or just:

    / <subrule> { print $subrule[1] } /

しかし名前つきキャプチャと名前つきルールはこの牧歌的な状況を阻害する。 あなたはすべての名前つきキャプチャと名前つきルールによりキー付けされた デフォルトの無名ハッシュの値が返されることを好むだろう。 疑問なのは番号付けされたキャプチャにハッシュインターフェースを強要するかどうか という点である。あるいはすべての場合においてサブルールの $1 を得るために、以下のようにする:

    / $sub:=<subrule> { print $sub{'1'} } /

しかし結果オブジェクトを配列として取り扱いたい理由があるので、

    / $sub:=<subrule> { process(@$sub) } /

これはサブルールによる番号付けされたキャプチャのすべてを処理する。 だからわたしは返却オブジェクトは状況に応じてハッシュか配列のいずれかのように振舞うものと 考える(そのような配列が0からではなく1から始まるように宣言されるだろうことに注意)。

[Update: We're steering clear of 1-based arrays for now.]

RFC 317: 正規表現に対する最適化情報へのアクセス

no-brainerのようである。すべてのそのような情報はなんにしろ Perl に対して 使用可能であり、可能ならばPerl の構文解析器、オプティマイザ、コードジェネレータに対して 与えられる。

RFC 331: $1 及び \1 表記の強化

わたしは本 RFC のタイトルが好きだ。すぐ近くのイントロダクションの新しい my のポリシーにフィットしている。 しかしながら、提案された実装には幾つかの困難な点がある。 配列 @/ の ステートメントごとのセッティングはわたしにとって見づらいものである。 むしろ、ステートメントの境界に関係することなくこの疑問の正規表現の外側で生存することの できるhypothetical 変数の一貫した視点を持つようにしたい。 先行する正規表現から $1 (とその同類)を参照する 必要がある場合、一時変数を使うべきだろう。

RFC 332: Regex: '/s'修飾子指定時の/$/を/\z/に等価にする

基本的に受理された別の RFC があるが、それは十分なものではない。 /s 修飾子は /m と共になくなった。 $ は常に文字列の終端にマッチし、 $$ は行の終端にマッチする (カレントプロセスID は$*PID になった。なので 衝突はしていない。しかしどれほどの頻度でカレントプロセスIDにマッチするパターンを 書こうと思うだろうか?)。

RFC 348: plain Perl code中の正規表現アサーション

本 RFCは幾つかの良い点を作り出すが、コードの表明構文はこうなるだろう:

    <( code )>

本 RFC はまた、Perl 5における local の 正規表現における異なる取り扱いのような特別な振る舞いを取り除くケースを作り出す。 しかしながら、 local の振る舞いは hypothesesを作り出すために必要であり、本 RFC が正しいにも関わらず 典型的なコード表明において必要とはならない。Perl 6 では、localization は temp によって行われ、これは Perl 5 がやっていたような hypothetical 変数ハックは行わない。その代わりに 陽な左辺値修飾子let がある。これは 変数の値を正規表現中のカレントポイントの成功にスコープするためのものである。 これらの hypothetical 変数は実際には本 RFCの提案するところよりも 範囲が広いものである。

Perl 5の $^R のハードワイアーされた 使用はPerl 6の対応する名前つき hypothetical 変数に変換される。

RFC 360: すべてのマッチのlistrefを返すためのmultiply matched groupsを許す

わたしは複数回マッチする可能性のある括弧は最後にマッチしたものではなく 自動的にリストを生成すると考える。これは何かの量指定子の内側で指示することのできない 場合のようなものではない・・・

以下は本 RFCの提案する解決策である:

    while ($text =~ /name:\s*(.*?)\n\s*
                    children:\s*(?:(?@\S+)[, ]*)*\n\s*
                    favorite\ colors:\s*(?:(?@\S+)[, ]*)*\n/sigx) {
        # 結果はこうなる:
        #  $1 = "John Abajace";
        #  $2 = ["Tom", "Dick", "Harry"]
        #  $3 = ["red", "green", "blue"]
    }

量指定子の内側の (...) の振る舞いの変更とは 別に、幾つかの理由でこの例を書き直したい:

これらの変更により、また空白の使用により、このサンプルの正規表現は以下のように なる:

    for ($text =~ m:ie[
                            name             \: \h*   (\N*?)            \n
                        \h* children         \: \h* [ (\S+) <[,\h]>* ]* \n
                        \h* favorite\ colors \: \h* [ (\S+) <[,\h]>* ]* \n
                      ]
          )
    {
             # 結果はこうなる:
             #  $1 = "John Abajace";
             #  $2 = ["Tom", "Dick", "Harry"]
             #  $3 = ["red", "green", "blue"]
    }

一度これらのものを使えば、可読性が向上していることに気づくだろうと考えている。 特に平行しているものを並べることはタイプエラーをなくすことになるだろう。

[Update: The :ie is now written :i:g.]

RFC 361: split()の単純化

本 RFC は五つの提案を持つ。一つ一つ見ていくことにしよう。

split に対する第一の主張は、それが実際に一つのものであろうとなかろうと 現在のところ正規表現として解釈されているということである(そう、 split '.', $foo はドットでsplitしない -- split /./, $foo と同じである)。 わたしはここで、splitが正規表現のときのみ正規表現として扱い、そうでないものは リテラルとして扱うように変更することを提案する。

もし split に対する最初の引数が型なしであれば、 即座にクォートされた文字列を評価するか、正規表現の遅延解釈のいずれかで正しく 解析される。別のパターンによってマッチした最初のデリミタでsplitすることもできる:

    split _/(,|;)/;

これはすべてのカンマかすべてのセミコロンのいずれかでsplitする。これは文字列中で 最初に見つかったものによって決定する。_ は正規表現に文字列を返すように強制する。 この場合は括弧によってキャプチャされたものである。

[Update: _ is now ~.]

空の終端にあるフィールドは現在抑制されている(しかし第三引数として -1が渡された場合には これはディセーブルされる)。 わたしはこの殻の終端にあるフィールドをデフォルトで保持することを提案する。

たぶんオーケーだろうが、古いコードを変換する方法が必要となる。 基本的にこれは、空白によるsplitが改行の後に余計なフィールドを返すので行われる。 しかし Perl 6 ではほとんどの改行はあらかじめ chomp される。

リストコンテキストにないとき、現在のsplitは @_ に splitの結果を格納する。この副作用を無くすことを提案したい。

良い。陽な代入に変換するのは十分簡単なことだ。

任意のコンテキストにおいて split ?pat? は その結果を @_に格納している。この副作用を なくすことを提案したい。

良い。誰かがこれを使っているとは思わない。

split ' ' (split / / ではない)は現在、空白で分割を行うが 先頭にあるからのフィールドを取り除いてしまう。この反則を取り除くことを提案したい。

疑問なのは、これが非常に便利なので何と置き換えるかということである。 別の慣習的なパターンを使うことができる:

    @array = split /<ws>/, $string;

あるいは、splitの引数が指定されていないときにのみ空白で分割するようにすることも できる。これは、しばしば第二引数を与える必要があるので古い構文とはうまく働かない。 しかし、=~ 演算子は今や任意の語のための topicalizer として働き、我々は変換を行うことができる:

    @array = split ' ', $string;

これを以下のようにする:

    @array = $string =~ split;

奇妙なことに、こう書いても良い:

    $string =~ (@array = split);

以下のようにさえできる:

    @array = split given $string;

しかし、オブジェクト指向表記が好ましいだろうと思う:

    @array = $string.split;

事実、split はすべての場合において関数であるわけではない。デフォルトの split は 単なる文字列のメソッドで、単項のドットを使う:

    @array = .split;

引数を取り扱うための第三引数があるが、これは以下のように指定することができる:

    @array = $string.split(limit => 3);

単語での分割のために、REXXが行っているような異なるメソッドを作ることもできる:

    @array = .words;

そして制限は第一引数として与えることができる:

    @array = .words(3);

しかしそのようなメソッドが必要となることはほとんどないだろう。なぜなら

    @array = m/ [ (\S*) \s* ]* /;

これがうまく働いてくれるからだ。.words メソッドの方が明らかに読みやすくはあるのだが・・・

幸運なことに、split は関数であり、このため わたしは黙示録 29まで意思決定を延期することができる :-)

[Update: At the moment I think there's a .words multimethod on strings.]

却下された RFC

RFC 135: マッチを使うときには??や//の場合にも陽にmを要求する

Squish that gnat... :-)

<-- A decent Perl parser is still going to have to keep track of whether a term or an operator is expected. And while we're simplifying the grammar in many ways, it's also the case that we're letting users install their own grammar rules to perform syntactic warpage. Besides, people like to write patterns with /.../. So rather than impoverishing Perl's syntax artificially, let's make the standard parser more accessible by writing it all in Perl 6 regexes. --> 寛大な Perl の構文解析器は語や演算子が期待されているかどうかを記憶する必要がある。 多くのやり方で文法を簡単にしてきたにも関わらず、構文的なwarpageを実行するための 独自のルールをユーザーにインストールさせる。さらに、人々は /.../ のようなパターンを書くのを好んでいる。 そのため Perl の構文を不自然に劣化させるよりは、標準の構文解析器を Perl 6の正規表現中ですべてを書くことでよりアクセスしやすいものにする。

RFC 145: Perlの正規表現のためのブレースマッチング

Good problem, not-so-good solution from a complexity point of view. わたしは存在するキャラクタクラスと後方参照の記法をてこ入れしたい。 後方参照に任意のマッチしたキャラクタの否定を伝える単純な方法があれば、 それをする。あるいはマッチしたキャラクタを思い出したときにそれを反転し、 後方参照を無視する?(否定的な面はネスとしたブラケットがおそらくは再帰的なパターンで 必要になるということである)

再帰はなんにしろ有効である -- 関数に対する引数を取り出すことは、 文字列の外で異なるブラケットルールを持っているかもしれない クォートされた文字列を取り扱うこと抜きにはできない。 \" というマッチングは文字列の内側にいるか 外側にいるかに依存するだろう。そのような再帰を与えることはしばしば必要であり、 わたしはこの構造を再帰的にすることが全面的に便利であるか自信がない。

tr/// がどのように働くかによって、 後方参照ジェネレータの中でキャラクタを再マッピングすることが一般には便利であろう とわたしは思う:

    (
     <[ \( \[ \{ \< ] =>
      [ \) \] \} \> ]> )

これはいずれかの左ブラケットにマッチするが $1 として 対応する右ブラケットを返す。しかし、文字列を変換するために"すでにある"機構を 使うべきだろう:

    my %closing = {
        '[' => ']',
        '(' => ')',
        '{' => '}',
        '<' => '>',
    };
    rule balanced {
        <![\[\(\{\<\]\)\}\>]>*  # any non-brackets
        [                       # followed by either
            $                   #   end of string
        |                       # or
            $b := <[[({<]>      #   an opening bracket
            <self>              #   containing a balanced expr
            %closing{$b}        #   followed by corresponding close bracket
            <self>              #   followed by a balanced expr
        ]
     }

RFC 164: =~, !~, m//, s///, tr//をmatch(), subst(), trade()で置き換える

すべての演算子はその他の名前に別名をつけることのできる名前付けの手段を持つだろう。 しかしパラメータの形式的な並びの再整理は少々難しいだろう。我々は効率的に行う inlining を必要としている。現在 // は 型なしコンテキストで評価しないので、それを任意の順番で行うサブルーチンやメソッドを 定義することは相対的に率直なものである。

    subst $string, /foo/, {"bar"}

[Update: We're defining standard .match, .subst, and .trans methods for strings as alternatives to the quoted syntaxes.]

RFC 197: 正規表現中のNumeric Value Ranges

もしこの道を進んでいくのなら、我々は正規表現におけるPerlの構文のすべてを再発明 する羽目になる。わたしはTMTOWTDIに反対するわけではないが、正規表現中の Perl コードの実行の方法にはもっと良い方法があると思うし、"成功" か "失敗"かの 状態を持つようにして、Perl コードのテスト範囲の方法もより良いものがあるだろう。 こういったことは構文的な warpageと共に行うことができるだろう。

任意のイベントで、 ()[] をオーバーロードすることは当てにならないし、 非数学者に対する不透明なものであることは言うまでもない。 標準のブール表明でこれを取り扱おう:

    / (\d+) <( $1 =~ 1..10 )> /

興味深いことに、これは以下のようにも書ける:

    / <( _/\d+/ =~ 1..10 )> /

[Update: That'd be <( ~/\d+/ ~~ 1..10 )> these days.]

RFC 198: Boolean正規表現

繰り返すが、通常のPerl の構文を複製するような新たな正規表現構文を発明する ことをわたしは好んでいない。わたしは我々が通常の Perl の構文を通して 関係する正規表現を相互に連結する豊かな方法を必要としていると考えている。 確かにこれは Perl の表明を特定する簡単な方法を持つことの助けになるだろう:

    / (\w+) <( %count{$1} > 3 )> /

しかし、カレントの正規表現のためにサブマッチ表明を外部で定義することを強制する ことになり、サブルーチンの呼び出しのところにインラインでコードを書くことを 思いとどまらせることになる。

わたしはサブマッチの大部分はタマネギの輪のようなもので、クロージャの中で キャプチャされた文字列で検索することにより単純に取り扱われるべきだと考える。 ブール式はクロージャの中に埋め込むことができるが、新しい :: 演算子は 車輪を再発明することなしにより正規表現らしく AND や OR の表明をするのを簡単にする。

提案にあるように、"fail" トークンが存在するようになるだろう、しかし、 \F ではなく <fail> とつづる。そして "ture" トークンは <null> とつづる。 :-)

RFC 261: perl valuesにおけるパターンマッチング

これはわたしに Prolog のユニフィケーションを思い出させた。 ここではあまり説明しないが、一般的に説明するには非常に難しいものであったなら わたしは不思議に思うだろう。これはおそらく 常にそれが主張することを行う単純な左辺値を理解している幸運で 典型的な Perl プログラマには 強力なコンセプトであろう。

マッチングの種類は構文的な warpage として提供することができるだろうが 便利な最適化を阻害する場合には確信できない。なんにしろ、この種のことは Perl 6のコアに入ることは、それが関数の引数リストに便利なように一般化して 強力でない限りはないだろう。この目的のためにはオーバーローディングの形式で 表すことになるだろうが、キーによって"型"が指定される。実際の型はより便利であろうと 思う。

RFC 308: Ban Perl hooks into regexes

我々はPerl で便利なように構文解析器を書きたい場合には Perl のコードにコールバックできるようにしなければならない。 yacc がどのように働いているかを考えよう。 Perl 5 で行っていることの一部は醜く、それはわたしも認める。 我々はそれを美しくできる。

しかし、Perl のポイント全体は非常に便利な "Krakken tentacles" を持つことである。 そしてわたしは別の言語にPerl の正規表現エンジンを押し込めることが難しくなることを 心配してはいない。:-)

RFC 316: chunkの処理とprefixマッチングのサポートのための正規表現修飾子

(無限配列を通じた)無限文字列はより便利なコンセプトのようである。これは 失敗して本 RFCにあるような結果を生成する拡張サブルーチンを簡単にする。しかし 拡張構文の必要なしに本 RFCでは特定されている。マッチはそれがパターンが終了せずに 文字列の終端に達したときは自然に失敗する。逐次的なマッチング(Incremental matching)は 同様に無限文字列を通して簡単に行うことができ、ユーザーインターフェースは 拡張ルールが文字列にどうにかして結び付けられるように単純にできる。

pos() は一般的な使用には低レベルなコンセプトであると 思う。確かに必要ではあるが、一つの正規表現が先行するものに継続することを 仮定する方法の必要があるとわたしは考える。しかし、一部の高レベルな構文構造の中では pos()\g/c を起動することなく 構文解析器を記述することが簡単である。

[Update: That turns out to be the :p modifier.]

<cut>

うん、まだ言うことはあるんだけど時間がきたようだ。これを読んで 良い方向で興奮してくれるといいんだけど。 しかし、あなたのあごがテーブルをたたいたときにその元気を無くしたなら(?)、 Damian の Exegesis 5 がここで言ったことのすべてをうまく説明してくれることを 期待する。