3.2. キーボードから文字列([a..zA..Z0..9])を入力し、これらの文字列を昇順・降順にソートする【JIS X 0213:2004(JIS2004)対応】。

JIS X 0213:2004(JIS2004) での問題

Windows Vista で採用された, JIS X 0213:2004 の文字集合すべてに対応させようと思うと, 上記のコードは正常に動作しません.
JIS X 0213:2004 に含まれる文字のうち, 303文字は Java の内部エンコーディングである UTF-16 において, 16bit + 16bit で表現されます(サロゲート・ペア).
Java の char は 16bit であるため, String#length() など, char を直接扱う API は正常に動作しなくなっています.
JavaSE5.0 で新たに追加された API を使用することで対応できるのですが, 少々面倒です...

/*
 * $Id: Example3_1_2.java 1641 2007-08-19 20:16:10Z nanasess $
 */
package jp.examples;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * Example3_1_2
 *
 * <p>
 *  3.1 Accepting series of numbers, strings from keyboard and sorting them ascending order.
 *   Supplementary Char Support.
 * </p>
 *
 * @author $Author: nanasess $
 * @version $Revision: 1641 $ $Date: 2007-08-20 05:16:10 +0900 (月, 20 8 2007) $
 * @see http://www.javainthebox.net/laboratory/J2SE1.5/MiscAPI/SupplementaryChar/SupplementaryChar.html
 */
public class Example3_1_2 {

    /**
     * 入力した文字列を昇順にソートし, 表示する(サロゲート・ペア対応).
     *
     * <pre>
     * JIS X 0213:2004 で定義された文字集合のうち, 303文字は,
     * UTF-16 において 16bit + 16bit で表現される(サロゲート・ペア).
     * サロゲート・ペアの文字列を正常に扱うためには, JavaSE 5.0 で追加された API を使う必要がある.
     * </pre>
     *
     * @throws Exception エラーが発生した場合
     */
    public static void main(String[] args) throws Exception {

        String s = "おえういあ";
        // サロゲート・ペアの文字列
        char[] ch = {(char)0xD801, (char)0xDC01,
                     (char)0xD801, (char)0xDC00};
        s = new String(ch) + s;

        // 文字列を List へ追加
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < s.length(); i++) {
            /*
             * サロゲート・ペア以外の char と上位サロゲートは, コードポイントが返されるが,
             * 下位サロゲートは char が返されるため,下位サロゲートを除外し,
             * コードポイントのみ String を生成する.
             */
            int codePoint = s.codePointAt(i);
            if (!Character.isLowSurrogate((char) codePoint)) {
                list.add(new String(new int[]{codePoint}, 0, 1));
            }
        }

        // 昇順にソート
        Collections.sort(list);

        // List の文字列を1文字ずつ表示
        int i = 1;
        StringBuilder sb = new StringBuilder();
        for (String str : list) {
            sb.append(str);
            System.out.println(i + ": " + str);
            i++;
        }

        // サロゲート・ペアがソートされているか確認してみる
        String expected = "あいうえお";
        char[] expectedChar = {(char)0xD801, (char)0xDC00,
                               (char)0xD801, (char)0xDC01};

        expected = expected + new String(expectedChar);

        // expected の順になっているはず.
        for (int j = 0; j < sb.length(); j++) {
            char c1 = expected.charAt(j);
            char c2 = sb.charAt(j);

            System.out.print(j + ":");
            System.out.print(" expected: " + Integer.toHexString(c1));
            System.out.print(" actual: " + Integer.toHexString(c2));
            System.out.println(" is " + (c1 == c2));
        }
    }
}

サロゲート・ペアの文字列を正常に入出力できる環境は少ないので, 直接 char の配列を生成して試してみました.
文字列のコードポイントを取得してチェックするのですが, サロゲート・ペアの文字列の場合のみ, 下位サロゲートが出現するので, これを利用してみます.

String#codePointAt(int) を使うと, 下記の int が返されます.

上記のコードでは, 下位サロゲートの char をチェックして, コードポイントを使って String を生成しています.

これを実行すると, 下記のような出力になります.

1: あ
2: い
3: う
4: え
5: お
6: ?
7: ?
0: expected: 3042 actual: 3042 is true
1: expected: 3044 actual: 3044 is true
2: expected: 3046 actual: 3046 is true
3: expected: 3048 actual: 3048 is true
4: expected: 304a actual: 304a is true
5: expected: d801 actual: d801 is true
6: expected: dc00 actual: dc00 is true
7: expected: d801 actual: d801 is true
8: expected: dc01 actual: dc01 is true

サロゲート・ペアである文字列は文字化けしていますが, char の順番を見てみると, 正常にソートされているのが解ります.
しかし, 大変ですね...(苦笑)