[PHP-users 31851] Re: 検索結果を第3引数に代入する時のpreg_match()の挙動について

lange @ e-mail.jp lange @ e-mail.jp
2007年 4月 7日 (土) 15:48:53 JST


tuchidaです。

長谷部さま
> この場合、$matches[1]と$matches[3]には空文字列が入るだろうと期待していたのに、
> 実際には$matches[1]に空文字列が入り、$matches[3]には値がセットされませんでした。
> 
> これはバグでしょうか。それとも仕様でしょうか。
 仕様だと思います。正規表現部位だけを抽出しますが。

'/^(string)?;(string)?;(string)?$/'
とは
'/^(?:(string)|);(?:(string)|);(?:(string)|)$/'
に置き換えられると思います。(要はサブパターンとマッチする
か、「何ともマッチしないか」という事です。ゆえにご希望の動
作を実現する為には ? を使わず

'/^(string|);(string|);(string|)$/'

 とすれば動作するかと思います。(php4.4.4では確認)

 しかし、サブパターンが失敗しているのに(preg_matchに
PREG_OFFSET_CAPTUREをつけて$matchesをvar_dumpすれば確認でき
ると思います)値が入ってしまっているのは、マッチした変数
の入る順番が「空の場合は無視する」ように*詰める処理*を行っ
てしまうと、次のようなプログラムの場合

(例:恥ずかしい例なのでツッコミはご容赦...
if( preg_match( "#http(s)?://(.*)#", $url, $matches (
{
 // $matches[1] を使って https か http かを判断
}

 $matches[1]には (.*) のデータが入るか (s) のデータが
入るかを判断し辛いからだと推測します。

php 4.4.4の ext/pcre/php_pcre.c:529行目- にも

 /*
  * If the number of captured subpatterns on this run is
  * less than the total possible number, pad the result
  * arrays with empty strings.
  */
 if (count < num_subpats) {
     for (; i < num_subpats; i++) {
         add_next_index_string(match_sets[i], empty_string, 1);
     }
 }

 とか書いてあるので、ここらへんなのかなーとか思ってます。
(C言語は素人なので、オオボケかもしれません...)

[テスト環境]
Windows XP
PHP 5.2.1

TurboLinux 10
PHP 4.4.4

tuchida <lange @ e-mail.jp>
http://bp2.jp/


PHP-users メーリングリストの案内