(携帯電話の表情フィルタ)Emojiとunicode特殊文字の処理


Emoji表情は使用中に、わけがわからずに消えたり、文字化けしたりして、データベースにインポートしたとき、文字が見えなくなったりして、不思議に消えてしまいました!
いくつかの主要な知識点:unicodeは論理的に17個のPlaneに分けられ、各Planeは65536個のコード点を保存する.Javaのcharは最大2バイト(16 bit)しかありません.つまり、65536文字しか記憶できませんが、0 x 10000より大きい文字はどう処理しますか.この方法はjavaも婉曲な方法で解決しましたCharacterですcodePoint()はintで格納されます.コードを直接見てください.コードにはコメントがあります.
package etna.core.util; import org.eclipse.jetty.util.StringUtil; import com.google.common.base.Strings; import com.google.common.hash.Hashing;/**  *

 * emoji , unicode , unicode emoji
 *  
 * 
 * :
 *
 * Unicode ,
 * BMP charAt(index) , length()
 * , codePointAt(index), codePointCount(0,str.lenght())

 * 
 * Unicode 17 (Plane), 65536( = 216) ,
 * 。
 * 0 (0000–FFFF): (Basic Multilingual Plane, BMP).
 * 1 (10000–1FFFF): (Supplementary Multilingual Plane, SMP).
 * 2 (20000–2FFFF): (Supplementary Ideographic Plane, SIP).
 * 3 (30000–3FFFF): (Tertiary Ideographic Plane, TIP).
 * 4 to 13 (40000–DFFFF)
 * 14 (E0000–EFFFF): (Supplementary Special-purpose Plane, SSP)
 * 15 (F0000–FFFFF) (Private Use Area, PUA)
 * 16 (100000–10FFFF), (Private Use Area, PUA)
 * 
 * :
 * : http://en.wikipedia.org/wiki/Emoji 
 * GITHUB: http://punchdrunker.github.io/iOSEmoji/
 * :1F300-1F5FF
 * :1F600-1F64F
 * :1F680-1F6FF
 * :2600-26FF
 * :2700-27BF
 * :1F100-1F1FF
 * :2B00-2BFF 2900-297F
 * :2300-23FF
 * : 2100–214F
 * : 303D 3200–32FF 2049 203C
 *  Private Use Area:E000-F8FF;
 *  High Surrogates D800..DB7F; 
 *  High Private Use Surrogates  DB80..DBFF
 *  Low Surrogates DC00..DFFF  D800-DFFF E000-F8FF
 *   :2000-200F 2028-202F 205F 2065-206F
 *   :IOS FE00-FE0F
 *
 *   * @author Yan.xu*@version 1.0*@date 2017年3月09日*/public class EmojiCharacterUtil{//エスケープ時private static final char unicode_separator='&';private static final char unicode_prefix='u';private static final char separator=':';private static boolean isEmojiCharacter(int codePoint){return(codePoint>=0 x 2600&&codePoint<=0 x 27 BF)/雑種記号と記号フォント||codePoint==0 x 303 D||codePoint==0 x 2049||codePoint==0 x 203 C|(codePoint>=0 x 2000&&codePoint<=0 x 200 F)//|(codePoint>=0 x 2028&&codePoint<=0 x 202 F)//||codePoint==0 x 205 F//|(codePoint>=0 x 2065&&codePoint<=0 x 206 F)///*句読点占有領域*/|(codePoint>=0 x 2100&&codePoint<=0 x 214 F)//アルファベット記号||(codePoint>=0 x 2300&&&codePoint<=0 x 23 FF)/各種技術記号|(codePoint>=0 x 2 B 00&&codePoint<=0 x 2 BFF)/矢印A|(codePoint>=0 x 290&&codePoint<=0 x 297 F)/矢印B|(codePoint>=0 x 3200&&codePoint<=0 x 32 FF)/中国語記号||(codePoint>=0 xD 800&&codePoint<=0 xDFF)/高低位置換子保持領域|(codePoint>=0 xE 000&&codePoint<=0 xF 8 FF)/プライベート保持領域|(codePoint>=0 xFE 00&&codePoint<=0 xFE 0 F)//変異セレクタ||codePoint>=0 x 10000;Planeが第2平面以上の場合、charは保存できません.すべてを回転します}/***emoji文字の文字列を可視文字ID*/public static String escape(String src){if(src==null){return null;        }         int cpCount = src.codePointCount(0, src.length());         int firCodeIndex = src.offsetByCodePoints(0, 0);         int lstCodeIndex = src.offsetByCodePoints(0, cpCount - 1);         StringBuilder sb = new StringBuilder(src.length());         for (int index = firCodeIndex; index <= lstCodeIndex;) {             int codepoint = src.codePointAt(index);             if (isEmojiCharacter(codepoint)) {                 String hash = Integer.toHexString(codepoint);                 sb.append(unicode_separator).append(hash.length()).append(unicode_prefix).append(separator).append(hash);             } else {                 sb.append((char) codepoint);             }         }         return sb.toString(); }/**解析可視文字識別文字列*/public static String reverse(String src){//対応する符号化された識別ビットif(src==null){return null;        }         StringBuilder sb = new StringBuilder(src.length());         char[] sourceChar = src.toCharArray();         int index = 0;         while (index < sourceChar.length) {             if (sourceChar[index] == unicode_separator) {                 if (index + 6 >= sourceChar.length) {                     sb.append(sourceChar[index]);                     index++;                     continue;//自分のフォーマット、汎用unicode形式とは相互に回転できないif(sourceChar[index+1]>='4'&&sourceChar[index+1]<='6'&&sourceChar[index+2]==unicode_prefix&&sourceChar[index+3]==separator){int length=Integer.parseInt(String.valueOf(sourceChar[index+1]));char[] hexchars = new char[length];//4~6ビットの配列を作成します.uncodeコードのHEX値for(int j=0;j='0'&&ch<='9')|(ch>='a'&&ch<='f')){hexchars[j]=ch;}else{//文字範囲がsb.append(sourceChar[index]);index++;break;                        }                     }                     sb.append(Character.toChars(Integer.parseInt(new String(hexchars), 16)));                     index += (4 + length);//4ビットプレフィックス+4-6ビット文字コード}else if(sourceChar[index+1]==unicode_prefix){//汎用文字の反転//第2平面上のものは、既に我々独自のトランスコードフォーマットを採用しているので、ここでは固定長4 char[hexchars=new char[4]; for(int j=0;j<4;j++){char ch=sourceChar[index+2+j];//2ビット識別コードif((ch>='0'&&ch<='9')|(ch>='a'&&ch<='f'){hexchars[j] = ch;//4ビット識別コード}else{//文字範囲がsb.append(sourceChar[index]);index++;break;                        }                         sb.append(Character.toChars(Integer.parseInt(String.valueOf(hexchars), 16)));                         index += (2 + 4);//2ビット接頭辞+4ビット文字コード}}else{sb.append(sourceChar[index]);index++;continue;                }             } else {                 sb.append(sourceChar[index]);                 index++;                 continue;             }         }         return sb.toString();     }     public static String filter(String src) {         if (src == null) {             return null;         }         int cpCount = src.codePointCount(0, src.length());         int firCodeIndex = src.offsetByCodePoints(0, 0);         int lstCodeIndex = src.offsetByCodePoints(0, cpCount - 1);         StringBuilder sb = new StringBuilder(src.length());         for (int index = firCodeIndex; index <= lstCodeIndex;) {             int codepoint = src.codePointAt(index);             if (!isEmojiCharacter(codepoint)) {                 System.err.println("codepoint:"+ Integer.toHexString(codepoint));                 sb.append((char) codepoint);             }             index += ((Character.isSupplementaryCodePoint(codepoint)) ? 2 : 1);         }         return sb.toString();     } }