[PHP-dev 884]mb_ereg_replaceについて

komura komura @ ma9.seikyou.ne.jp
2003年 9月 20日 (土) 08:51:01 JST


komura です。こちらでは初めてです。

mb_ereg_replace() について、少し気になる点がありました。
今まで問題になったような投稿などは見つけられませんでしたし、正規表現の
書き方によって回避することができますので、大きな問題ではないのかも
しれませんが、報告します。

環境は、RedHat Linux 7.3、PHP 4.3.3 ですが、Windows 版の
PHP-4.3.3-Win32 でも同じ問題を確認しました。


1. 無限ループ
   以下の行を実行すると、無限ループになります。

   echo mb_ereg_replace( ".*", "", "" );


2. 結果に NULL が追加される
   '?' や '*' を使って置き換えを行うと、後ろに NULL が追加されます。

// $s = mb_ereg_replace( "C?$", "Z", "ABC" );
   $s = mb_ereg_replace( "C*$", "Z", "ABC" );
   var_dump( $s );
   echo bin2hex( $s );
   --
   string(5) "ABZZ"
   41425a5a00


一応、ソースを調べてみたのですが、私にとってはマルチバイト正規表現の
部分は複雑で、詳しくは分かりません。


調べたことを書いておきます。

1. の無限ループに関しては、マルチバイト正規表現のオプションを空にして
実行すると、無限ループにはなりませんでした。

   mb_regex_set_options( "" );
   echo mb_ereg_replace( ".*", "", "" );

PHP 4.3.3 のソースを確認してみましたが、 ext/mbstring/mbregex.c の以下の
部分で無限ループになっているようです。

 3301   if (bufp->used > 0) {
 3302     switch ((enum regexpcode)bufp->buffer[0]) {
 3303     case begbuf:
 3304     begbuf_match:
 3305       if (range > 0) {
 3306         if (startpos > 0) return -1;
 3307         else {
 3308           val = re_match(bufp, string, size, 0, regs);
 3309           if (val >= 0) return 0;
 3310           return val;
 3311         }
 3312       }
 3313       break;

 ...

 3328   if (bufp->options & MBRE_OPTIMIZE_ANCHOR) {
 3329     if (bufp->options&MBRE_OPTION_SINGLELINE) {
 3330       goto begbuf_match;
 3331     }
 3332     anchor = 1;
 3333   }

MBRE_OPTION_SINGLELINE が有効になっていると、無限ループになるようです。
mb_ereg_replace() で指定するオプションに、's' か、'p'(デフォルト) を
指定すると、MBRE_OPTION_SINGLELINE が有効になります。


また、マルチバイト正規表現の処理に oniguruma が組み込まれている、
CVS 版の php5-200309180130 でも試してみましたが、Segmentation fault を
起こします。

$ php -v
PHP 5.0.0b2-dev (cli) (built: Sep 18 2003 17:01:41)
Copyright (c) 1997-2003 The PHP Group
Zend Engine v2.0.0-dev, Copyright (c) 1998-2003 Zend Technologies

$ php -r 'mb_ereg_replace( "C*$", "Z", "ABC" );'
セグメンテーション違反です

-- 
komura <komura @ ma9.seikyou.ne.jp>


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