恥ずかしながら知りませんでした.

あまりお読みの方はなじみがないかもしれませんが、unicode.org(ftp://www.unicode.org/Public/6.0.0/ucd/Unihan.zip)から漢字の属性データを落としてAccess2010で加工し、JavaのRuleBasedCollatorの入力となるUTF-8エンコーディングのテキストファイルを作っています.このテキストファイルを入力にJavaのRUleBasedCollatorの漢字の並び順を指定するのです.データを加工するだけで実に2週間かかりました.unicode.orgのデータもボランティアがやっているとのことで、pinyin(拼音)や画数が必ずしも正確ではありません.またデータも全部そろっているわけではありません.間違いはメールで確認したり、不足な漢字の読みのデータは、漢字データベース(http://kanji-database.sourceforge.net/database/strokes.html)のデータを使わせていただいたりと結構大変なのです.従来はBMP面の漢字だけでしたがUnicodeの補助文字まで対応したものにしようとしています.
 
そこで問題なのですが、JavaのRuleBasedCollatorです.RuleBasedCollatorはUnicodeの補助文字に対応していたのでしょうか?データが出来上がる前に一応簡単なデータで試して動くことを確認しました.
作ったのは次のようなプログラムです.Locale.JAPANESEのコレータに漢字の並び順定義を加えてテストしました.\u00BEはJavaの普通のコレーションだと"a"の前に来る文字です.
 
import java.text.RuleBasedCollator;
import java.text.Collator;
import java.util.Arrays;
import java.util.Locale;
import java.text.ParseException;
public class RuleBasedCollatorTest {
  public static void main(String args) {
    RuleBasedCollator ja_Collator = (RuleBasedCollator)Collator.getInstance(Locale.JAPANESE);
    String ja_Rules=ja_Collator.getRules();
     String supplementaryString = "& \u00BE < \u1F003 < \u1F002 < \u1F001 < \u1F000"
             + "& \u0063 < \u1F319 < \u1F318 < \u1F317 < \u1F316";
     RuleBasedCollator specialJaCollator=null;
     try{
       specialJaCollator = new RuleBasedCollator(ja_Rules + supplementaryString);
     }
     catch (ParseException pe){
       System.err.println("RuleBasedCollator ParserException");
       System.err.println("description="+pe.getMessage());
       System.exit(1);
     }
     String
srcStringArray={"a","A","b","B","c","C","d","D","\u00BE","\u01F003","\u01F002","\u01F001","\u01F000",
                 "\u01F319","\u01F318","\u01F317","\u01F316"};
     printArray(srcStringArray,"Source=");
     Arrays.sort(srcStringArray,specialJaCollator);
     printArray(srcStringArray,"Result=");
     System.exit(0);
  }
  private static void printArray(String array, String desc){
      StringBuffer buf = new StringBuffer();
      String str;
      int
codePoint;
      System.out.print(desc);
      for (int i = 0; i < array.length; i++) {
        str=array[i];
        codePoint=toCodePointArray(str);
        for (int j = 0; j < codePoint.length; j++){
          buf.append("\\u" + Integer.toHexString(codePoint[j]));
        }
        buf.append(",");
      }
      System.out.println(buf.substring(0, buf.length() - 1) );
  }
  private static int toCodePointArray(String str) {
      int len = str.length(); // the length of str
      int
acp = new int[str.codePointCount(0, len)];
      int j = acp.length;     // an index for acp
      for (int i = len; i > 0; i = str.offsetByCodePoints(i, -1)) {
          acp[--j] = str.codePointBefore(i);
      }
      return acp;
  }
}
 
ところが出てきた結果は、以下のようなもので何か変です.
 
Source=\u61,\u41,\u62,\u42,\u63,\u43,\u64,\u44,\ube,\u1f0\u30\u33,\u1f0\u30\u32,\u1f0\u30\u31,\u1f0\u30\u30,\u1f3\u31\u39,\u1f3\u31\u38,\u1f3\u31\u37,\u1f3\u31\u36
Result=\ube,\u61,\u41,\u62,\u42,\u63,\u43,\u64,\u44,\u1f0\u30\u30,\u1f0\u30\u31,\u1f0\u30\u32,\u1f0\u30\u33,\u1f3\u31\u36,\u1f3\u31\u37,\u1f3\u31\u38,\u1f3\u31\u39
 
どう見ても補助文字がうまく認識されていません.それもあってかソート結果は期待通りにはなりません.原因わかりますか?私は全然わかりませんでした.JDKやらいろいろあたってもわからずに最後に、
 
 
に行き着きました.するとそこにはこう書いてあります.
 
「補助文字を直接表現できる文字エンコーディング方式を採用すれば、Java プログラミング言語のソースファイル内で補助文字をきわめて簡単に取り扱うことができます。たとえば、UTF-8 は最適なエンコーディング方式です。補助文字を直接表現できない文字エンコーディング方式を使用する場合に備えて、Java プログラミング言語には Unicode エスケープ構文が用意されています。この Unicode エスケープ構文には、補助文字を直接表現する機能は追加されていません。その代わり、文字を UTF-16 で表現した場合の 2 つのコード単位に対応する 2 つの連続した Unicode エスケープによって補助文字が表されます。たとえば、補助文字 U+20000 は "\uD840\uDC00と表されます。通常、これらのエスケープシーケンスをユーザが直接書くのは困難です。そのため、必要な補助文字をサポートするエンコーディング方式で文字を書いた後、native2ascii などの変換ツールを使用して文字をエスケープシーケンスに変換することをお勧めします。」
 
エッ!Javaのソースコードって補助文字直接かけないの~!? やっとここで間違いに気がつきました.恥ずかしながら知りませんでした.でもまさしくここにも書いてあるように「これらのエスケープシーケンスをユーザが直接書くのは困難」です.計算するのも面倒だったので、補助文字を文字参照するXMLファイルを作り、XSLTでUTF-16のテキストファイルに落として、それをバイナリエディタで見て、そこからサロゲートペアーに書き直しました.こんな具合です.
 
String supplementaryString = "& \u00BE < \uD801\uDC03 < \uD801\uDC02 < \uD801\uDC01 < \uD801\uDC00" + "& \u0063 < \uD83C\uDF19 < \uD83C\uDF18 < \uD83C\uDF17 < \uD83C\uDF16";
String[] srcStringArray={"a","A","b","B","c","C","d","D","\u00BE","\uD801\uDC03","\uD801\uDC02","\uD801\uDC01","\uD801\uDC00", "\uD83C\uDF19","\uD83C\uDF18","\uD83C\uDF17","\uD83C\uDF16"};
 
すると今度は補助文字がちゃんと認識されて次のような結果が出てきました.しかしJavaって不便ですね~!
 
Source=\u61,\u41,\u62,\u42,\u63,\u43,\u64,\u44,\ube,\u10403,\u10402,\u10401,\u10400,\u1f319,\u1f318,\u1f317,\u1f316
Result=\ube,\u10403,\u10402,\u10401,\u10400,\u61,\u41,\u62,\u42,\u63,\u1f319,\u1f318,\u1f317,\u1f316,\u43,\u64,\u44
 
うまく補助文字でもRuleBasedCollatorは動いています.というわけで、今度はAccessで作ったUTF-8のファイルからRuleBasedCollatorの入力Stringを作り出して動かしました.するとParserExceptionで一発でこけてしまいます.メッセージも変で、
 
RuleBasedCollator ParserException
description=The entries <都 and <都 are adjacent in the rules, but have conflicting strengths: A character can't be unequal to itself.
 
(続く)