CakeFest 2024: The Official CakePHP Conference

繰り返し

繰り返し (repetition) は、量指定子 (quantifier) を使って指定します。 量指定子は、以下の要素の後に付けることが出来ます。

  • 個々の文字。エスケープされた文字も含む
  • メタ文字 . (ドット)
  • 文字クラス
  • 後方参照 (次のセクションを参照)
  • カッコで括られたサブパターン(言明は除く - 別記参照)

汎用の量指定子 (general repetition quantifier) は、波カッコの中に 2 つの数をカンマで区切って記述したもので、マッチ可能な 最小と最大の繰り返し数を指定します。ただし、65536 以上の数は 指定できません。さらに、最初の数は 2 番目の数以下である必要があります。 例えば、パターン

      z{2,4}
      
は、"zz", "zzz", "zzzz" にマッチします。閉じ波カッコだけでは 特別な意味を持ちません。カンマを残したまま 2 番目の数だけを省略すると、 繰り返しの上限が設定されません。 2 番目の数字とカンマの両方を省略すると、 必要なマッチの数を過不足なく指定できます。つまり、
      [aeiou]{3,}
      
は、最短で 3 回母音が連続するものにマッチし、 もっと多く連続する場合にもマッチします。一方、
      \d{8}
      
は、ぴったり 8 桁の数字にのみマッチします。開き波カッコは、 量指定子を置けない場所、つまり量指定子の構文に適合しない場所に 記述された場合、文字リテラルとして解釈されます。例えば、 {,6} は量指定子ではなく、4つの文字からなる文字リテラルとなります。

{0} という量指定子の指定も可能です。 直前の項目および量指定子が存在しないという指定になります。

簡単(および歴史的な互換性)のため、よく使われる 3 つの量指定子には、 次のような 1 文字の省略型があります。

単一文字の量指定子
* {0,} と同じ
+ {1,} と同じ
? {0,1} と同じ

たとえば

      (a?)*
      
の様に、「文字無し」にマッチし得るサブパターンの後ろに 上限指定の無い量指定子を記述すると、無限ループができてしまう可能性が あります。

以前のバージョンの Perl および PCRE は、このようなパターンに関して コンパイル時にエラーを発生していました。しかし、有用な場合もあるので、 現在はこのようなパターンも許可されています。ただし、 繰り返しが指定されたサブパターンが文字無しにマッチすると、 ループは強制的に中断されます。

デフォルトでは、量指定子は「貪欲 (greedy)」です。つまり、 残りのパターンが失敗しない限りにおいて、(許可された回数の上限まで) 出来るだけ多くマッチします。 この動作が問題を生じる場合もあります。 そのよく知られた例としては、 C プログラムのコメントに マッチさせようとする場合が挙げられます。 /* と */ との間が コメントですが、コメント中にも文字 * や / が現れる可能性があります。 そこで、C のコメントにマッチさせようとして、パターン

      /\*.*\*/
      
を使って、文字列
      /* first comment */  not comment  /* second comment */
      
に対して、マッチングを行うと、文字列全体にマッチしてしまい上手く行きません。 .* 要素が貪欲であるためです。

しかし、量指定子の後に疑問符を付けると、貪欲さは消え、 できるだけ少ない回数だけマッチします。このため、パターン

      /\*.*?\*/
      
は、C コメントに正しくマッチします。量指定子の他の意味は変化せず、 マッチの回数だけが変更されます。疑問符のこの使用法と、 量指定子としての使用法とを混同しないようにしてください。 このように疑問符には 2 種類の使用法があるため、
      \d??\d
      
のように 2 重に使うこともできます。 このパターンは、可能であれば 1 桁の数字にマッチします。 パターンの残り部分がそうでないとマッチできない場合に限り、 2 桁の数字にもマッチします。

PCRE_UNGREEDY オプション(Perl ではこのオプションは利用できません)を設定すると、 量指定子は、デフォルトで貪欲でなくなり、 各量指定子の後ろに疑問符をつけてはじめて貪欲になります。言いかえると、 疑問符のデフォルトの動作を逆転します。

量指定子の後ろに + を記述すると「独占的 (possessive)」 になります。可能なだけ多くの文字を取り込み、パターンの残りの部分のマッチの際に 取り込んだ文字を戻すことはしません。したがって、パターン .*abc は "aabc" にマッチしますが、.*+abc はマッチしません。 これは、.*+ が対象文字列のすべてを取り込んでしまうためです。 独占的量指定子を使って処理速度を向上させることができます。

カッコを使ったサブパターンに、最小の繰り返し回数(1 以上)や 最大の繰り返し回数を指定した場合、その繰り返し数の大きさに応じて、 コンパイル済みのパターンが用いる記憶領域がより多く必要となります。

パターンが .* または .{0,} で始まっており、PCRE_DOTALL オプション(Perl の /s に相当)が設定されている(つまり、 . が改行文字にもマッチする)場合、そのパターンは暗黙的に 固定パターンになります。.* もしくは .{0,} の後に続くパターンは、 対象文字列のすべての位置でマッチングが行われますが、パターン全体としては 対象文字列の始端以外でマッチングを再試行しても無駄だからです。PCRE は、 このようなパターンについては、その前に \A が記述されているものとして 扱います。こうした最適化を利用するために、 対象文字列が改行文字を含んでいなことが明らかな場合は、 .* で始まるパターンに対し PCRE_DOTALL を設定するか、 ^ を用いて明示的に固定パターンとなるよう指定すると良いでしょう。

キャプチャ用サブパターンを繰り返した場合、キャプチャされる値は、 繰り返しの最後でマッチした部分文字列です。例えば、

      (tweedle[dume]{3}\s*)+
      
を "tweedledum tweedledee" にマッチングさせた場合、キャプチャされる 部分文字列は、 "tweedledee" です。しかし、キャプチャ用サブパターンが ネストしている場合、キャプチャされる値は、より前の繰り返しで 得られたものとなる可能性があります。例えば
      /(a|(b))+/
      
を "aba" にマッチングさせると、キャプチャされた部分文字列の 2 番目のものは、 "b" になります。

add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top