2012-03-29

Force.com : Apex で文字列に含まれる半角カタカナを全角カタカナに置換したい


Apex で文字列に含まれる半角カタカナを全角カタカナに置換したい



したくない!
所詮は、置換したい文字の対応 Map を作成してそれで置換しているに過ぎない :-)。



○ 文字列に含まれる半角カタカナを全角カタカナに置換したい

  • 半角カタカナの範囲は「FF61-FF9F」とする
  • 該当する濁点を含む文字が存在しない場合は[全角カタカナ + 全角濁点]とする
  • 該当する半濁点を含む文字が存在しない場合は[全角カタカナ + 全角半濁点]とする
■ 実装クラス
public class StringUtility {

    /** インスタンス */
    private static final StringUtility instance = new StringUtility();

    /** 16 進数表記 → 10 進数表記置換 Map */
    private Map<String, Integer> hexadecimalToDecimalMap;

    /** 半角カナ・置換 Map */
    private Map<String, String> replaceMap;
    /** 半角カナ・置換 Map Unicode */
    private Map<String, String> replaceHexadecimalMap;

    /** 濁点・置換 Map */
    private Map<String, String> replaceDakutenMap;
    /** 濁点・置換 Map Unicode */
    private Map<String, String> replaceDakutenHexadecimalMap;

    /** 半濁点・置換 Map */
    private Map<String, String> replaceHandakutenMap;
    /** 半濁点・置換 Map Unicode */
    private Map<String, String> replaceHandakutenHexadecimalMap;

    /**
     * コンストラクタ
     */
    private StringUtility() {

        // 16 進数表記 → 10 進数表記置換 Map 作成
        hexadecimalToDecimalMap = new Map<String, Integer>();
        hexadecimalToDecimalMap.put('0', 0);
        hexadecimalToDecimalMap.put('1', 1);
        hexadecimalToDecimalMap.put('2', 2);
        hexadecimalToDecimalMap.put('3', 3);
        hexadecimalToDecimalMap.put('4', 4);
        hexadecimalToDecimalMap.put('5', 5);
        hexadecimalToDecimalMap.put('6', 6);
        hexadecimalToDecimalMap.put('7', 7);
        hexadecimalToDecimalMap.put('8', 8);
        hexadecimalToDecimalMap.put('9', 9);
        hexadecimalToDecimalMap.put('A', 10);
        hexadecimalToDecimalMap.put('B', 11);
        hexadecimalToDecimalMap.put('C', 12);
        hexadecimalToDecimalMap.put('D', 13);
        hexadecimalToDecimalMap.put('E', 14);
        hexadecimalToDecimalMap.put('F', 15);

        // 半濁点・置換 Map 作成
        replaceHandakutenHexadecimalMap = new Map<String, String>();
        replaceHandakutenHexadecimalMap.put('FF8A,FF9F', '30D1');    // パ
        replaceHandakutenHexadecimalMap.put('FF8B,FF9F', '30D4');
        replaceHandakutenHexadecimalMap.put('FF8C,FF9F', '30D7');
        replaceHandakutenHexadecimalMap.put('FF8D,FF9F', '30DA');
        replaceHandakutenHexadecimalMap.put('FF8E,FF9F', '30DD');
        replaceHandakutenMap = new Map<String, String>();
        for(String key : replaceHandakutenHexadecimalMap.keySet()) {
            replaceHandakutenMap.put(unicodeToString(key.split(',', 0)), unicodeToString(replaceHandakutenHexadecimalMap.get(key).split(',', 0)));
        }

        // 濁点・置換 Map 作成
        replaceDakutenHexadecimalMap = new Map<String, String>();
        replaceDakutenHexadecimalMap.put('FF76,FF9E', '30AC');    // ガ
        replaceDakutenHexadecimalMap.put('FF77,FF9E', '30AE');
        replaceDakutenHexadecimalMap.put('FF78,FF9E', '30B0');
        replaceDakutenHexadecimalMap.put('FF79,FF9E', '30B2');
        replaceDakutenHexadecimalMap.put('FF7A,FF9E', '30B4');
        replaceDakutenHexadecimalMap.put('FF7B,FF9E', '30B6');    // ザ
        replaceDakutenHexadecimalMap.put('FF7C,FF9E', '30B8');
        replaceDakutenHexadecimalMap.put('FF7D,FF9E', '30BA');
        replaceDakutenHexadecimalMap.put('FF7E,FF9E', '30BC');
        replaceDakutenHexadecimalMap.put('FF7F,FF9E', '30BE');
        replaceDakutenHexadecimalMap.put('FF80,FF9E', '30C0');    // ダ
        replaceDakutenHexadecimalMap.put('FF81,FF9E', '30C2');
        replaceDakutenHexadecimalMap.put('FF82,FF9E', '30C5');
        replaceDakutenHexadecimalMap.put('FF83,FF9E', '30C7');
        replaceDakutenHexadecimalMap.put('FF84,FF9E', '30C9');
        replaceDakutenHexadecimalMap.put('FF8A,FF9E', '30D0');    // バ
        replaceDakutenHexadecimalMap.put('FF8B,FF9E', '30D4');
        replaceDakutenHexadecimalMap.put('FF8C,FF9E', '30D6');
        replaceDakutenHexadecimalMap.put('FF8D,FF9E', '30D9');
        replaceDakutenHexadecimalMap.put('FF8E,FF9E', '30DC');
        replaceDakutenHexadecimalMap.put('FF73,FF9E', '30F4');    // ヴ
        replaceDakutenMap = new Map<String, String>();
        for(String key : replaceDakutenHexadecimalMap.keySet()) {
            replaceDakutenMap.put(unicodeToString(key.split(',', 0)), unicodeToString(replaceDakutenHexadecimalMap.get(key).split(',', 0)));
        }

        // 半角カナ・置換 Map 作成
        replaceHexadecimalMap = new Map<String, String>();
        replaceHexadecimalMap.put('FF61', '3002');    // Halfwidth CJK punctuation
        replaceHexadecimalMap.put('FF62', '300C');
        replaceHexadecimalMap.put('FF63', '300D');
        replaceHexadecimalMap.put('FF64', '3001');
        replaceHexadecimalMap.put('FF65', '30FB');    // Halfwidth Katakana variants
        replaceHexadecimalMap.put('FF66', '30F2');
        replaceHexadecimalMap.put('FF67', '30A1');
        replaceHexadecimalMap.put('FF68', '30A3');
        replaceHexadecimalMap.put('FF69', '30A5');
        replaceHexadecimalMap.put('FF6A', '30A7');
        replaceHexadecimalMap.put('FF6B', '30A9');
        replaceHexadecimalMap.put('FF6C', '30E3');
        replaceHexadecimalMap.put('FF6D', '30E5');
        replaceHexadecimalMap.put('FF6E', '30E7');
        replaceHexadecimalMap.put('FF6F', '30C3');
        replaceHexadecimalMap.put('FF70', '30FC');
        replaceHexadecimalMap.put('FF71', '30A2');
        replaceHexadecimalMap.put('FF72', '30A4');
        replaceHexadecimalMap.put('FF73', '30A6');
        replaceHexadecimalMap.put('FF74', '30A8');
        replaceHexadecimalMap.put('FF75', '30AA');
        replaceHexadecimalMap.put('FF76', '30AB');
        replaceHexadecimalMap.put('FF77', '30AD');
        replaceHexadecimalMap.put('FF78', '30AF');
        replaceHexadecimalMap.put('FF79', '30B1');
        replaceHexadecimalMap.put('FF7A', '30B3');
        replaceHexadecimalMap.put('FF7B', '30B5');
        replaceHexadecimalMap.put('FF7C', '30B7');
        replaceHexadecimalMap.put('FF7D', '30B9');
        replaceHexadecimalMap.put('FF7E', '30BB');
        replaceHexadecimalMap.put('FF7F', '30BD');
        replaceHexadecimalMap.put('FF80', '30BF');
        replaceHexadecimalMap.put('FF81', '30C1');
        replaceHexadecimalMap.put('FF82', '30C4');
        replaceHexadecimalMap.put('FF83', '30C6');
        replaceHexadecimalMap.put('FF84', '30C8');
        replaceHexadecimalMap.put('FF85', '30CA');
        replaceHexadecimalMap.put('FF86', '30CB');
        replaceHexadecimalMap.put('FF87', '30CC');
        replaceHexadecimalMap.put('FF88', '30CD');
        replaceHexadecimalMap.put('FF89', '30CE');
        replaceHexadecimalMap.put('FF8A', '30CF');
        replaceHexadecimalMap.put('FF8B', '30D2');
        replaceHexadecimalMap.put('FF8C', '30D5');
        replaceHexadecimalMap.put('FF8D', '30D8');
        replaceHexadecimalMap.put('FF8E', '30DB');
        replaceHexadecimalMap.put('FF8F', '30DE');
        replaceHexadecimalMap.put('FF90', '30DF');
        replaceHexadecimalMap.put('FF91', '30E0');
        replaceHexadecimalMap.put('FF92', '30E1');
        replaceHexadecimalMap.put('FF93', '30E2');
        replaceHexadecimalMap.put('FF94', '30E4');
        replaceHexadecimalMap.put('FF95', '30E6');
        replaceHexadecimalMap.put('FF96', '30E8');
        replaceHexadecimalMap.put('FF97', '30E9');
        replaceHexadecimalMap.put('FF98', '30EA');
        replaceHexadecimalMap.put('FF99', '30EB');
        replaceHexadecimalMap.put('FF9A', '30EC');
        replaceHexadecimalMap.put('FF9B', '30ED');
        replaceHexadecimalMap.put('FF9C', '30EF');
        replaceHexadecimalMap.put('FF9D', '30F3');
        replaceHexadecimalMap.put('FF9E', '309B');
        replaceHexadecimalMap.put('FF9F', '309C');
        replaceMap = new Map<String, String>();
        for(String key : replaceHexadecimalMap.keySet()) {
            replaceMap.put(unicodeToString(key.split(',', 0)), unicodeToString(replaceHexadecimalMap.get(key).split(',', 0)));
        }
    }

    /**
     * Unicode を文字列に変換する
     * @param unicodes unicode 配列
     * @return 文字列
     */
    public String unicodeToString(String[] unicodes) {
        List<Integer> chars = new List<Integer>();
        for(String unicode : unicodes) {
            Integer c = 0;
            for(Double i=0, len=unicode.length(); i<len; i++) {
                c += (Math.pow(16, (len - i - 1)).intValue() * hexadecimalToDecimalMap.get(unicode.substring(i.intValue(), i.intValue()+1)));
            }
            chars.add(c);
        }
        return String.fromCharArray(chars);
    }

    /**
     * 置換が必要か判定する
     * ※ 半角カナ(FF61-FF9F)が含まれている場合置換を必要とする
     * @param s 文字列
     * @return true: 必要/false: 不必要
     */
    public Boolean isReplace(String s) {
        return !Pattern.matches('^[^\\uFF61-\\uFF9F]{1,}$', s);
    }

    /**
     * 置換
     * @param s 文字列
     * @return 置換文字列
     */
    public String replace(String s) {
        if(s == null || s == '') return s;

        // 半濁点
        if(!isReplace(s)) return s;
        for(String key : replaceHandakutenMap.keySet()) {
            s = s.replaceAll(key, replaceHandakutenMap.get(key));
        }

        // 濁点
        if(!isReplace(s)) return s;
        for(String key : replaceDakutenMap.keySet()) {
            s = s.replaceAll(key, replaceDakutenMap.get(key));
        }

        // 半角カナ
        if(!isReplace(s)) return s;
        for(String key : replaceMap.keySet()) {
            s = s.replaceAll(key, replaceMap.get(key));
        }

        return s;
    }

    /**
     * インスタンス取得
     * @return インスタンス
     */
    public static StringUtility getInstance() {
        return StringUtility.instance;
    }
}

■ 実行
// インスタンス取得
StringUtility sutility = StringUtility.getInstance();

// 置換する文字列作成(半角「パガア」)
String[] codes = new String[]{'FF8A','FF9F', 'FF76', 'FF9E', 'FF71'};
String str = sutility.unicodeToString(codes);

// 置換
String restr = sutility.replace(str);



◆ メモ

  • Apex クラスは UTF-8
  • Apex クラスで半角カタカナを記述しないが吉、ぽい
  • 置換 Map を修正した場合は isReplace() メソッドの修正も忘れないこと



◇ 環境

  • Salesforce - Developer Edition - API バージョン 24.0



◇ 関連記事


0 件のコメント:

コメントを投稿