よしだです

Ruby が UTF-8 対応するのを待っていられなくて,不完全ながら
UTF-8 に対応させてみました。

UTF-8 対応しているのは,

  ・ -KU オプション,および $KCODE='UTF8'
  ・ メソッド名,変数名など
  ・ 一部の正規表現 ('.' など)
  ・ String#split

対応していないのは

  ・ 一部の正規表現 ('\w', '\W', '\b' など)
  ・ 正規表現の文字コードオプション
  ・ もともとマルチバイト化されていない機能 (tr, chop など)
  ・ jcode.rb
  ・ その他?

です。('\w' は EUC や SJIS でも挙動不審のような?)

UTF-8 が使えると,

  http://www.bekkoame.ne.jp/~yoshidam/Hello.rb
  http://www.bekkoame.ne.jp/~yoshidam/Hello.gif (ソースの画像)

のようなプログラムが書けるようになります。

UTF-8 対応のエディタ,端末等が無ければ試してみることができな
いかも知れませんが,御意見,御感想をお聞かせ下さい。


diff -ur ruby-1.2.1/parse.y ruby-1.2.1+utf8/parse.y
--- ruby-1.2.1/parse.y	Thu Nov 26 17:25:45 1998
+++ ruby-1.2.1+utf8/parse.y	Sat Jan 16 01:39:19 1999
@@ -3021,8 +3021,11 @@
     while (is_identchar(c)) {
 	tokadd(c);
 	if (ismbchar(c)) {
+	  int i, len = ismbchar(c);
+	  for (i = 0; i < len; i++) {
 	    c = nextc();
 	    tokadd(c);
+	  }
 	}
 	c = nextc();
     }
diff -ur ruby-1.2.1/re.c ruby-1.2.1+utf8/re.c
--- ruby-1.2.1/re.c	Mon Nov  9 18:11:50 1998
+++ ruby-1.2.1+utf8/re.c	Wed Jan 13 15:39:13 1999
@@ -95,7 +95,8 @@
 #define KCODE_EUC   FL_USER2
 #define KCODE_SJIS  FL_USER3
 #define KCODE_FIXED FL_USER4
-#define KCODE_MASK (KCODE_EUC|KCODE_SJIS)
+#define KCODE_MASK (KCODE_EUC|KCODE_SJIS|KCODE_UTF8)
+#define KCODE_UTF8  FL_USER5
 
 static int reg_kcode = 
 #ifdef RUBY_USE_EUC
@@ -104,7 +105,11 @@
 # ifdef RUBY_USE_SJIS
     KCODE_SJIS;
 # else
+#  ifdef RUBY_USE_UTF8
+    KCODE_UTF8
+#  else
     KCODE_NONE;
+#  endif
 # endif
 #endif
 
@@ -127,6 +132,15 @@
 }
 
 static void
+kcode_utf8(reg)
+    struct RRegexp *reg;
+{
+    FL_UNSET(reg, KCODE_MASK);
+    FL_SET(reg, KCODE_UTF8);
+    FL_SET(reg, KCODE_FIXED);
+}
+
+static void
 kcode_none(reg)
     struct RRegexp *reg;
 {
@@ -150,6 +164,9 @@
       case KCODE_SJIS:
 	re_mbcinit(MBCTYPE_SJIS);
 	break;
+      case KCODE_UTF8:
+	re_mbcinit(MBCTYPE_UTF8);
+	break;
     }
 }	  
 
@@ -166,6 +183,9 @@
       case KCODE_SJIS:
 	re_mbcinit(MBCTYPE_SJIS);
 	break;
+      case KCODE_UTF8:
+	re_mbcinit(MBCTYPE_UTF8);
+	break;
     }
 }
 
@@ -230,6 +250,9 @@
 	      case KCODE_SJIS:
 		str_cat(str, "s", 1);
 		break;
+	      case KCODE_UTF8:
+		str_cat(str, "u", 1);
+		break;
 	    }
 	}
     }
@@ -290,6 +313,8 @@
 	    kcode = "euc"; break;
 	  case KCODE_SJIS:
 	    kcode = "sjis"; break;
+	  case KCODE_UTF8:
+	    kcode = "utf8"; break;
 	  default:
 	    break;
 	}
@@ -942,6 +967,8 @@
 	return "SJIS";
       case KCODE_EUC:
 	return "EUC";
+      case KCODE_UTF8:
+	return "UTF8";
       default:
 	return "NONE";
     }
@@ -970,6 +997,11 @@
 	reg_kcode = KCODE_SJIS;
 	re_mbcinit(MBCTYPE_SJIS);
 	break;
+      case 'U':
+      case 'u':
+	reg_kcode = KCODE_UTF8;
+	re_mbcinit(MBCTYPE_UTF8);
+	break;
       default:
       case 'N':
       case 'n':
@@ -1022,7 +1054,11 @@
 #ifdef RUBY_USE_SJIS
     re_mbcinit(MBCTYPE_SJIS);
 #else
+#ifdef RUBY_USE_UTF8
+    re_mbcinit(MBCTYPE_UTF8);
+#else
     re_mbcinit(MBCTYPE_ASCII);
+#endif
 #endif
 #endif
 
diff -ur ruby-1.2.1/regex.c ruby-1.2.1+utf8/regex.c
--- ruby-1.2.1/regex.c	Sun Jan 10 01:43:21 1999
+++ ruby-1.2.1+utf8/regex.c	Sat Jan 16 01:38:23 1999
@@ -2284,7 +2284,7 @@
     }
     else if (translate && !ismbchar(c)) {
       while (big < bend) {
-	if (ismbchar(*big)) big++;
+	if (ismbchar(*big)) big+=ismbchar(*big);
 	else if (translate[*big] == c) break;
 	big++;
       }
@@ -2292,7 +2292,7 @@
     else {
       while (big < bend) {
 	if (*big == c) break;
-	if (ismbchar(*big)) big++;
+	if (ismbchar(*big)) big+=ismbchar(*big);
 	big++;
       }
     }
@@ -2300,7 +2300,7 @@
     if (slow_match(little, little+llen, big, bend, translate))
       return big - bsave;
 
-    if (ismbchar(*big)) big++;
+    if (ismbchar(*big)) big+=ismbchar(*big);
     big++;
   }
   return -1;
@@ -2566,6 +2566,7 @@
 	    break;
 	  case MBCTYPE_EUC:
 	  case MBCTYPE_SJIS:
+	  case MBCTYPE_UTF8:
 	    for (j = 0x80; j < (1 << BYTEWIDTH); j++) {
 	      if (mbctab[j])
 		fastmap[j] = 1;
@@ -2587,6 +2588,7 @@
 	    break;
 	  case MBCTYPE_EUC:
 	  case MBCTYPE_SJIS:
+	  case MBCTYPE_UTF8:
 	    for (j = 0x80; j < (1 << BYTEWIDTH); j++) {
 	      if (!mbctab[j])
 		fastmap[j] = 1;
@@ -2906,7 +2908,7 @@
 	const char *d = string + startpos;
 
 	if (ismbchar(*d)) {
-	  range--, startpos++;
+	  range-=ismbchar(*d), startpos+=ismbchar(*d);
 	  if (!range)
 	    break;
 	}
@@ -3492,10 +3494,10 @@
 	  PREFETCH;
 	  /* Match anything but a newline, maybe even a null.  */
 	  if (ismbchar(*d)) {
-	    if (d + 1 == dend || d[1] == '\n' || d[1] == '\0')
+	    if (d + ismbchar(*d) >= dend || d[1] == '\n' || d[1] == '\0')
 	      goto fail;
 	    SET_REGS_MATCHED;
-	    d += 2;
+	    d += ismbchar(*d) + 1;
 	    break;
 	  }
 	  if (((TRANSLATE_P()) ? translate[*d] : *d) == '\n')
@@ -3844,8 +3846,8 @@
 	  PREFETCH;
 	  if (IS_A_LETTER(d))
             goto fail;
-	  if (ismbchar(*d) && d + 1 != dend)
-	    d++;
+	  if (ismbchar(*d) && d + ismbchar(*d) < dend)
+	    d += ismbchar(*d);
 	  d++;
           SET_REGS_MATCHED;
 	  break;
@@ -4347,6 +4349,26 @@
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
 };
 
+static const unsigned char mbctab_utf8[] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0
+};
+
+
 const unsigned char *mbctab = mbctab_ascii;
 int current_mbctype = MBCTYPE_ASCII;
 
@@ -4366,6 +4388,10 @@
   case MBCTYPE_SJIS:
     mbctab = mbctab_sjis;
     current_mbctype = MBCTYPE_SJIS;
+    break;
+  case MBCTYPE_UTF8:
+    mbctab = mbctab_utf8;
+    current_mbctype = MBCTYPE_UTF8;
     break;
   }
 }
diff -ur ruby-1.2.1/regex.h ruby-1.2.1+utf8/regex.h
--- ruby-1.2.1/regex.h	Fri Oct  2 13:45:47 1998
+++ ruby-1.2.1+utf8/regex.h	Wed Jan 13 15:13:35 1999
@@ -175,6 +175,7 @@
 #define MBCTYPE_ASCII 0
 #define MBCTYPE_EUC 1
 #define MBCTYPE_SJIS 2
+#define MBCTYPE_UTF8 3
 
 extern int current_mbctype;
 
diff -ur ruby-1.2.1/string.c ruby-1.2.1+utf8/string.c
--- ruby-1.2.1/string.c	Mon Nov  9 18:11:51 1998
+++ ruby-1.2.1+utf8/string.c	Sat Jan 16 01:38:58 1999
@@ -931,7 +931,7 @@
 	repl = reg_regsub(val, str, regs);
 	str_cat(result, RSTRING(repl)->ptr, RSTRING(repl)->len);
 	if (BEG(0) == END(0)) {
-	    int len = ismbchar(RSTRING(str)->ptr[END(0)])?2:1;
+	    int len = ismbchar(RSTRING(str)->ptr[END(0)]) + 1;
 	    /*
 	     * Always consume at least one character of the input string
 	     * in order to prevent infinite loops.
@@ -1014,7 +1014,7 @@
 	str_cat(result, RSTRING(val)->ptr, RSTRING(val)->len);
 
 	if (BEG(0) == END(0)) {
-	    int len = ismbchar(RSTRING(str)->ptr[END(0)])?2:1;
+	    int len = ismbchar(RSTRING(str)->ptr[END(0)]) + 1;
 
 	    /*
 	     * Always consume at least one character of the input string
@@ -2101,13 +2101,13 @@
 	    if (start == end && BEG(0) == END(0)) {
 		if (last_null == 1) {
 		    if (ismbchar(RSTRING(str)->ptr[beg]))
-			ary_push(result, str_substr(str, beg, 2));
+			ary_push(result, str_substr(str, beg, ismbchar(RSTRING(str)->ptr[beg]) + 1));
 		    else
 			ary_push(result, str_substr(str, beg, 1));
 		    beg = start;
 		}
 		else {
-		    start += ismbchar(RSTRING(str)->ptr[start])?2:1;
+		    start += ismbchar(RSTRING(str)->ptr[start]) + 1;
 		    last_null = 1;
 		    continue;
 		}

-- 
    吉田正人  INS エンジニアリング(株)
              都市情報システム事業部
    yoshidam / inse.co.jp
    yoshidam / yoshidam.net