Unicode 文字列ーUTF-8変換をする処理メソッドを整理する。(Javaで)

過去、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_う_
_あ_い_う_+_=_あ_い_う_