過去、Unicode 文字列を変換する処理を書いたが、
https://github.com/yipuran/yipuran-core/blob/master/src/main/java/org/yipuran/util/StringUtils.java
https://github.com/yipuran/yipuran-core/blob/master/src/main/java/org/yipuran/util/SJutil.java
http://oboe2uran.hatenablog.com/entry/2019/04/25/164759
http://oboe2uran.hatenablog.com/entry/2018/12/24/185040
http://oboe2uran.hatenablog.com/entry/2018/12/23/183835
少し効率が悪いのを反省して、処理を書き直すことにした。
Unicode以外の文字列が混ざってもうまく読み込めるものを作ることにした。
クラス名も改め、Unicodes である。
import java.util.regex.Pattern; /** * Unicodes */ public final class Unicodes{ private static Pattern ptn2; private static Pattern ptn4; private Unicodes(){ ptn2 = Pattern.compile("\\\\u[0-9a-fA-F]{4}"); ptn4 = Pattern.compile("\\\\\\\\u[0-9a-fA-F]{4}"); } public static Unicodes of(){ return new Unicodes(); } /** * Unicode文字列に変換する("あ" → "\u3042") */ public static String encode(String string){ if (string == null || string.isEmpty()) return ""; StringBuilder sb = new StringBuilder(); for(int i=0; i < string.length(); i++){ sb.append(String.format("\\u%04X", Character.codePointAt(string, i))); } return sb.toString(); } /** * Unicode文字列→UTF-8 */ public static String decode(String unicode){ if (unicode == null || unicode.isEmpty()) return ""; String[] cs = unicode.split("\\\\u"); int[] cp = new int[cs.length - 1]; for(int i=0;i < cp.length; i++){ cp[i] = Integer.parseInt(cs[i + 1], 16); } return new String(cp, 0, cp.length); } /** * 1文字だけのUnicode文字→UTF-8 */ public String character(String unicode){ if (unicode==null || unicode.isEmpty()) return ""; if (ptn4.matcher(unicode).matches()){ return new String(new int[]{ Integer.parseInt(unicode.substring(3), 16) }, 0, 1); }else if(ptn2.matcher(unicode).matches()){ return new String(new int[]{ Integer.parseInt(unicode.substring(2), 16) }, 0, 1); }else{ return unicode; } } /** * Unicode表現+Unicode以外表現の混在文字列→UTF-8 */ public String parse(String str){ if (str==null || str.isEmpty()) return ""; String s = ptn4.matcher(str).replaceAll(m-> new String(new int[]{ Integer.parseInt(m.group().substring(3), 16) }, 0, 1) ); return ptn2.matcher(s).replaceAll(m-> new String(new int[]{ Integer.parseInt(m.group().substring(2), 16) }, 0, 1) ); } }
これは、Java9 から採用された正規表現の一括置換、
java.util.regex.Matcher の
String replaceAll(Function<MatchResult, String> replacer)
を使っているので、Java9 以上の環境でなければダメだ。
簡単なテストコード
String s0 = "\u3042"; System.out.println(s0); System.out.println(Unicodes.of().character(s0)); String s1 = "\\u3042"; System.out.println(s1); System.out.println(Unicodes.of().character(s1)); String s2 = "\\\\u3042"; System.out.println(s2); System.out.println(Unicodes.of().character(s2)); String ustr = Unicodes.encode("あいうabc123()+=%"); System.out.println(ustr); System.out.println(Unicodes.decode(ustr)); /* _あ_い_う_+_=_あ_い_う_ の文字列 */ String str = "_\\\\u3042_\\\\u3044_\\\\u3046_\\\\uff0b_\\\\uFF1D_\\u3042_\\u3044_\u3046_"; System.out.println(str); System.out.println(Unicodes.of().parse(str));
結果
あ あ \u3042 あ \\u3042 あ \u3042\u3044\u3046\u0061\u0062\u0063\u0031\u0032\u0033\u0028\u0029\uFF0B\uFF1D\uFF05 あいうabc123()+=% _\\u3042_\\u3044_\\u3046_\\uff0b_\\uFF1D_\u3042_\u3044_う_ _あ_い_う_+_=_あ_い_う_