まつもと ゆきひろです

In message "[ruby-dev:8529] Re: String#rindex for multi-byte chars"
    on 99/12/05, YANAGAWA Kazuhisa <kjana / os.xaxon.ne.jp> writes:

|> 一応、仕様です。正しいマッチのためにはstartposが文字境界であ
|> ることを期待しているつもりです。マルチバイトならstartposをど
|> うこうってのは、やってないと思うんですが。
|
|まあ,これは regexp.c:re_search() をながめてたら ismbchar() でどうこ
|う,っていうのを見付けただけなので.でも現状でも一番最後の文字について
|はマルチバイト文字でもちゃんとマッチするように見えるので,ほかでもなん
|とかするつもりだったのではと邪推したのです :-)

あんまり考えてなかったです。

で、土曜の夜に風邪引いたあたまでつらつらと考えてみたのですが、
問題なのは、

|半端なマルチバイト文字の一部をどう扱う
|か,というのをちゃんとする必要はあるでしょうが.

という点です。/\244/みたいなパターンがマルチバイト文字の一部
にマッチできるっていう仕様がいかんのかもしれませんが。

つーわけで、パターンの先頭がマルチバイト文字の一部にマッチす
る可能性がある場合以外には、startposのオフセットを文字単位に
正規化するコードを書いてみました。

なんかうまく動いているようです。また様子を見てください。

diff -u -1 -r1.3 regex.h
--- regex.h	1999/08/24 08:21:54	1.3
+++ regex.h	1999/12/06 02:18:36
@@ -79,2 +79,3 @@
 #define RE_OPTIMIZE_NO_BM    (RE_OPTIMIZE_EXACTN<<1)
+#define RE_OPTIMIZE_BMATCH   (RE_OPTIMIZE_NO_BM<<1)
 
--- regex.c	1999/11/11 04:08:26	1.9
+++ regex.c	1999/12/06 02:18:45
@@ -2628,2 +2629,3 @@
 	    fastmap[p[2]] = 2;
+	  bufp->options |= RE_OPTIMIZE_BMATCH;
 	}
@@ -2830,4 +2832,6 @@
 		 single-byte chars.  We must reject them. */
-	      if (c < 0x100)
+	      if (c < 0x100) {
 		fastmap[beg] = 2;
+		bufp->options |= RE_OPTIMIZE_BMATCH;
+	      }
 	      else if (ismbchar(beg))
@@ -2950,2 +2954,29 @@
     re_compile_fastmap(bufp);
+  }
+
+  /* Adjust startpos for mbc string */
+  if (current_mbctype && startpos>0 && !(bufp->options&RE_OPTIMIZE_BMATCH)) {
+    int i = 0;
+
+    if (range > 0) {
+      while (i<size) {
+	i += mbclen(string[i]);
+	if (startpos <= i) {
+	  startpos = i;
+	  break;
+	}
+      }
+    }
+    else {
+      int w;
+
+      while (i<size) {
+	w = mbclen(string[i]);
+	if (startpos < i + w) {
+	  startpos = i;
+	  break;
+	}
+	i += w;
+      }
+    }
   }