サロゲートペア文字列の操作

目的

Vistaが世に出てから、サロゲートペア文字列の扱いに頭を悩ませているエンジニアの方々も多いと思うのですが、「java サロゲートペア substring」とかで検索しても、なぜかそれっぽい記事が出てきません。
毎回実装するたび忘れて再実装しちゃうので、作ったクラスをメモしときます。
(もしかして、汎用的なUtilityとかあるのか?)

ソース

public final class CodePointUtils {
private CodePointUtils() {
}

/**
* サロゲートペア文字を置換.
*
* @param str
* 文字列
* @param replacement
* 置換文字列
* @return 置換後文字列
*/
public static String replaceSurrogatePair(String str, String replacement) {
StringBuilder sb = new StringBuilder();
char ach = str.toCharArray();

int cp = 0;
int len = str.length();
for (int i = 0; i < len; i += Character.charCount(cp)) {
cp = Character.codePointAt(ach, i);
if (!Character.isSupplementaryCodePoint(cp)) {
sb.append(String.valueOf(Character.toChars(cp)));
} else {
sb.append(replacement);
}
}

return sb.toString();
}

/**
* 文字列を開始位置から終了位置まで取り出す.
*
* @param str 文字列
* @param beginIndex 開始位置
* @param endIndex 終了位置
* @return 文字列
*/
public static String substring(String str, int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > length(str)) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}

StringBuilder sb = new StringBuilder();

char ach = str.toCharArray();

int beginOffset = str.offsetByCodePoints(0, beginIndex);
int endOffset = str.offsetByCodePoints(0, endIndex);

int cp = 0;
for (int i = beginOffset; i < endOffset; i += Character.charCount(cp)) {
cp = Character.codePointAt(ach, i);
sb.append(String.valueOf(Character.toChars(cp)));
}

return sb.toString();
}

/**
* 文字数を取得.
*
* @param str 文字列
* @return 文字数
*/
public static int length(String str) {
return str.codePointCount(0, str.length());
}
}


参考

http://www.ibm.com/developerworks/jp/ysl/library/java/j-unicode_surrogate/