最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Java實(shí)現(xiàn)查找并移除字符串中的Emoji

 更新時(shí)間:2024年03月14日 08:19:48   作者:LetterZ  
Emoji 實(shí)際上是 UTF-8 (Unicode) 字符集上的特殊字符,這篇文章主要介紹了如何使用Java實(shí)現(xiàn)查找并移除字符串中的Emoji,感興趣的可以了解下

一、基礎(chǔ)知識

  • Emoji 實(shí)際上是 UTF-8 (Unicode) 字符集上的特殊字符,多數(shù)基本 Emoji 都被分配到 Unicode 編碼表 1 號平面的 U+1F300–1F6FF 和 U+1F900–1FAFF 兩個(gè)區(qū)域,由2個(gè)字符組成。
  • 膚色修飾:大多數(shù)與人相關(guān)的 Emoji 默認(rèn)是黃色的,所以后來引入了五個(gè)新碼點(diǎn)作為修飾符:U+1F3FB、U+1F3FCU+1F3FD、U+1F3FEU+1F3FF。膚色修飾符追加到現(xiàn)有的 Emoji 后形成新的樣式: U+1F44B(?? ) + U+1F3FD= ????
  • 符號變體或組合:一個(gè)普通的字后連接一個(gè)或多個(gè)變體、組合標(biāo)識(字符),組合形成的 Emoji : U+25C0+U+FE0F= ?? U+27A1+U+FE0F= ?? 1+U+FE0F+U+20E3= 1??
  • 國旗:每個(gè)國旗由2個(gè)地區(qū)標(biāo)識符組合而成,地區(qū)標(biāo)識符的對應(yīng)碼點(diǎn)范圍為U+1F1E6~U+1F1FF,等同于2個(gè)指定范圍的普通 Emoji 字符組成。 U+1F1E8+U+1F1F3= ????
  • 零寬度連接符(ZWJ):多個(gè)基礎(chǔ) Emoji 通過零寬度連接符(U+200D)形成的復(fù)雜 Emoji: ??+U+200D+??= ??‍?? ??+U+200D+??‍+U+200D+??= ??‍??‍?? ??+U+200D+??‍+U+200D+??+U+200D+??= ??‍??‍??‍??
  • 序列:一個(gè)基礎(chǔ) Emoji 加上多個(gè)標(biāo)簽字符 (U+E0020~ U+E007F )并以 Tag Cancel(U+E007)結(jié)尾,組合形成一個(gè)復(fù)雜 Emoji: U+1F3F4(??) +U+E0067+U+E0062+U+E0065+U+E006E+U+E0067+U+E007F= ??????????????
  • 特殊符號: 特殊符號只有1個(gè)字符,有些符號在某些環(huán)境下會被當(dāng)做Emoj處理:?、?、?;

Unicode 只是約定了碼點(diǎn)到 emoji 的映射關(guān)系,并沒有約定 Emoji 圖形,每個(gè) Emoji 字體文件可以按照自己的想法設(shè)計(jì) Emoji。

二、解決方案

除了一些特殊符號形式的 Emoji,其他Emoji至少有2個(gè)字符,所以先根據(jù)第二個(gè)字符類型判斷是否為Emoji,使用Character.UnicodeBlock.ofCharacter.getType方法判定每個(gè)字符的類型。

通過第二個(gè)字符類型判斷當(dāng)前2個(gè)字符為 Emoji 后: 1)判斷是否有后續(xù)修飾 2)判斷處理國旗類型;判斷處理膚色修飾;判斷處理 Emoji 序列標(biāo)簽;判斷處理零寬度連接符;判斷處理連續(xù)變體、組合標(biāo)識;按照普通 Emoji 處理;

處理單字符的特殊符號,這一類型內(nèi)有的屬于 Emoji,有的不是,目前全部簡單的按照普通 Emoji 處理;

三、完整代碼

package com.zpf.tool;

import java.util.List;

public class EmojiUtil {

    public static boolean isEmojiNationalFlag(int codePoint) {
        return codePoint >= 127462 && codePoint <= 127487;
    }

    // String str = new String(new int[]{0x1F44B, 0x1F3FD}, 0, 2);
    public static boolean isEmojiSkinColor(int codePoint) {
        return codePoint >= 127995 && codePoint <= 127999;
    }

    // String str = new String(new int[]{0x1F3F4, 0xE0067, 0xE0062, 0xE0065, 0xE006E, 0xE0067, 0xE007F}, 0, 7);
    public static boolean isEmojiTagEnd(int codePoint) {
        return codePoint == 917631;
    }

    public static boolean isEmojiTagSpec(int codePoint) {
        return codePoint >= 917536 && codePoint <= 917630;
    }

    public static boolean isEmojiDecorateBlock(Character.UnicodeBlock block) {
        if (block == null) {
            return false;
        }
        return block.equals(Character.UnicodeBlock.VARIATION_SELECTORS)
                || block.equals(Character.UnicodeBlock.VARIATION_SELECTORS_SUPPLEMENT)
                || block.equals(Character.UnicodeBlock.COMBINING_HALF_MARKS)
                || block.equals(Character.UnicodeBlock.COMBINING_MARKS_FOR_SYMBOLS)
                || block.equals(Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS)
                || block.equals(Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS_SUPPLEMENT);
    }

    public static void pickAllEmoji(CharSequence data, StringBuilder removeResult, List<String> emojiList) {
        if (removeResult == null && emojiList == null) {
            return;
        }
        if (removeResult != null) {
            removeResult.delete(0, removeResult.length());
        }
        if (emojiList != null) {
            emojiList.clear();
        }
        if (data == null || data.length() == 0) {
            return;
        }
        StringBuilder emojiBuilder = new StringBuilder();
        int i = 0;
        int j;
        Character.UnicodeBlock block;
        while (i < data.length()) {
            if (i + 1 < data.length()) {
                block = Character.UnicodeBlock.of(data.charAt(i + 1));
                if (isEmojiDecorateBlock(block) || Character.UnicodeBlock.LOW_SURROGATES.equals(block)) {
                    if (i + 2 >= data.length()) {
                        emojiBuilder.append(data, i, i + 2);
                        break;
                    }
                    j = handleNationalFlag(data, i, emojiBuilder, emojiList);
                    if (i != j) {
                        i = j;
                        continue;
                    }
                    j = handleHumanSkin(data, i, emojiBuilder, emojiList);
                    if (i != j) {
                        i = j;
                        continue;
                    }
                    j = handleTagSequence(data, i, emojiBuilder, emojiList);
                    if (i != j) {
                        i = j;
                        continue;
                    }
                    emojiBuilder.append(data, i, i + 2);
                    i = handleNextChar(data, i + 2, emojiBuilder, emojiList);
                    continue;
                }
            }
            recordEmoji(emojiBuilder, emojiList);
            int type = Character.getType(data.charAt(i));
            if (type == (int) Character.OTHER_SYMBOL) {//特殊符號一律按照Emoji處理
                if (emojiList != null) {
                    emojiList.add(String.valueOf(data.charAt(i)));
                }
            } else if (removeResult != null) {
                removeResult.append(data.charAt(i));
            }
            i++;
        }
        recordEmoji(emojiBuilder, emojiList);
    }

    private static int handleNextChar(CharSequence data, int i, StringBuilder emojiBuilder, List<String> emojiList) {
        if (i >= data.length()) {
            return i;
        }
        char nextChar = data.charAt(i);
        if (nextChar == '\u200D') {//零寬度連接符
            emojiBuilder.append(nextChar);
            return i + 1;
        }
        int j = i;
        Character.UnicodeBlock block;
        while (j < data.length()) {
            nextChar = data.charAt(j);
            block = Character.UnicodeBlock.of(nextChar);
            if (isEmojiDecorateBlock(block)) {
                emojiBuilder.append(nextChar);
                j++;
            } else {
                break;
            }
        }
        if (i != j) {
            recordEmoji(emojiBuilder, emojiList);
        }
        return j;
    }

    private static int handleNationalFlag(CharSequence data, int i, StringBuilder emojiBuilder, List<String> emojiList) {
        int codePoint = Character.codePointAt(data, i);
        if (isEmojiNationalFlag(codePoint)) {//處理國旗類型
            recordEmoji(emojiBuilder, emojiList);//提交未處理
            if (i + 3 < data.length()) {
                codePoint = Character.codePointAt(data, i + 2);
                if (isEmojiNationalFlag(codePoint)) {
                    emojiBuilder.append(data, i, i + 4);
                    recordEmoji(emojiBuilder, emojiList);
                    i = i + 4;
                }
            }
            i = i + 2;
        }
        return i;
    }

    private static int handleHumanSkin(CharSequence data, int i, StringBuilder emojiBuilder, List<String> emojiList) {
        if (i + 3 >= data.length()) {
            return i;
        }
        int codePoint = Character.codePointAt(data, i + 2);
        if (isEmojiSkinColor(codePoint)) {//膚色修飾
            emojiBuilder.append(data, i, i + 4);
            recordEmoji(emojiBuilder, emojiList);
            i = i + 4;
        }
        return i;
    }

    private static int handleTagSequence(CharSequence data, int i, StringBuilder emojiBuilder, List<String> emojiList) {
        if (i + 3 >= data.length()) {
            return i;
        }
        int codePoint = Character.codePointAt(data, i + 2);
        if (isEmojiTagSpec(codePoint)) {
            emojiBuilder.append(data, i, i + 4);
            i = i + 4;
            while (i < data.length()) {
                codePoint = Character.codePointAt(data, i);
                if (isEmojiTagSpec(codePoint)) {
                    emojiBuilder.append(data, i, i + 2);
                    i = i + 2;
                } else if (isEmojiTagEnd(codePoint)) {
                    emojiBuilder.append(data, i, i + 2);
                    recordEmoji(emojiBuilder, emojiList);
                    i = i + 2;
                    break;
                } else { //error
                    break;
                }
            }
            emojiBuilder.delete(0, emojiBuilder.length());
        } else if (isEmojiTagEnd(codePoint)) {
            emojiBuilder.append(data, i, i + 4);
            recordEmoji(emojiBuilder, emojiList);
            i = i + 4;
        }
        return i;
    }

    private static void recordEmoji(StringBuilder builder, List<String> emojiList) {
        if (builder != null && builder.length() > 0) {
            if (emojiList != null) {
                emojiList.add(builder.toString());
            }
            builder.delete(0, builder.length());
        }
    }

}

以上就是使用Java實(shí)現(xiàn)查找并移除字符串中的Emoji的詳細(xì)內(nèi)容,更多關(guān)于Java查找并移除字符串中Emoji的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 解決springboot文件上傳提示臨時(shí)文件夾不存在問題

    解決springboot文件上傳提示臨時(shí)文件夾不存在問題

    這篇文章主要介紹了解決springboot文件上傳提示臨時(shí)文件夾不存在問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringBoot通過源碼探究靜態(tài)資源的映射規(guī)則實(shí)現(xiàn)

    SpringBoot通過源碼探究靜態(tài)資源的映射規(guī)則實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot通過源碼探究靜態(tài)資源的映射規(guī)則實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • 淺談一下Java中的幾種JVM級別的鎖

    淺談一下Java中的幾種JVM級別的鎖

    這篇文章主要介紹了淺談一下Java中的幾種JVM級別的鎖,當(dāng)存在安全漏洞時(shí),也必須有相應(yīng)的防護(hù)措施。順應(yīng)這種趨勢,虛擬"鎖"被發(fā)明出來,以解決線程的安全問題。在這篇文章中,我們將研究多年來出現(xiàn)的?Java?中幾種典型的?JVM?級鎖,需要的朋友可以參考下
    2023-08-08
  • SpringBoot實(shí)體多層嵌套判空字段的方式

    SpringBoot實(shí)體多層嵌套判空字段的方式

    這篇文章主要介紹了SpringBoot實(shí)體多層嵌套如何判空字段,最近在公司了接了個(gè)需求:需要開發(fā)一個(gè)中間系統(tǒng),進(jìn)行三方聯(lián)調(diào),文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2024-09-09
  • SpringBoot實(shí)現(xiàn)數(shù)據(jù)庫讀寫分離的3種方法小結(jié)

    SpringBoot實(shí)現(xiàn)數(shù)據(jù)庫讀寫分離的3種方法小結(jié)

    為了提高系統(tǒng)的讀寫性能和可用性,讀寫分離是一種經(jīng)典的數(shù)據(jù)庫架構(gòu)模式,在SpringBoot應(yīng)用中,有多種方式可以實(shí)現(xiàn)數(shù)據(jù)庫讀寫分離,本文將介紹三種主實(shí)現(xiàn)方案,大家可以根據(jù)需要自行選擇
    2025-04-04
  • Java實(shí)用工具之StringJoiner詳解

    Java實(shí)用工具之StringJoiner詳解

    這篇文章主要介紹了Java實(shí)用工具之StringJoiner詳解,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • Java實(shí)現(xiàn)本地文件批量重命名的示例代碼

    Java實(shí)現(xiàn)本地文件批量重命名的示例代碼

    本文主要介紹了Java實(shí)現(xiàn)本地文件批量重命名的示例代碼,主要步驟為獲取指定目錄下的所有文件,對每個(gè)文件進(jìn)行修改,將修改后的文件名賦給該文件,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • 使用Java繪制心形動(dòng)畫的代碼示例

    使用Java繪制心形動(dòng)畫的代碼示例

    Java動(dòng)態(tài)愛心代碼是一種簡單而精美的動(dòng)態(tài)效果,這篇文章主要介紹了使用Java繪制心形動(dòng)畫的代碼示例,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-06-06
  • SpringBoot封裝MinIO工具的實(shí)現(xiàn)步驟

    SpringBoot封裝MinIO工具的實(shí)現(xiàn)步驟

    MinIO是一款高性能、開源、兼容Amazon?S3?API的分布式對象存儲系統(tǒng),Spring?Boot通過封裝配置與工具類,標(biāo)準(zhǔn)化設(shè)計(jì)降低開發(fā)復(fù)雜度,提升開發(fā)效率與系統(tǒng)穩(wěn)定性,感興趣的可以了解一下
    2025-07-07
  • SpringBoot集成Redis實(shí)現(xiàn)訂單超時(shí)管理的詳細(xì)步驟

    SpringBoot集成Redis實(shí)現(xiàn)訂單超時(shí)管理的詳細(xì)步驟

    文章描述了如何使用Redis來處理超時(shí)支付訂單,包括引入依賴、配置連接、定義實(shí)體類、實(shí)現(xiàn)服務(wù)和監(jiān)聽器等步驟,文章討論了優(yōu)化方案、注意事項(xiàng)以及Redis的性能和可靠性問題,感興趣的朋友跟隨小編一起看看吧
    2026-03-03

最新評論

汽车| 布尔津县| 荔浦县| 新邵县| 八宿县| 嘉定区| 博爱县| 府谷县| 鲜城| 裕民县| 新民市| 保亭| 峨边| 阜新| 夹江县| 海阳市| 常山县| 肇源县| 密云县| 镇远县| 渭南市| 怀集县| 兴国县| 崇礼县| 大渡口区| 金华市| 宁强县| 浏阳市| 鹿泉市| 乐昌市| 霸州市| 宁陵县| 安岳县| 台南市| 孟津县| 碌曲县| 阜宁县| 阿图什市| 灵丘县| 罗城| 绥中县|