【问题标题】:How to decode unwell-formed hex string of emoji character like "`1f1e81f1f3`"?如何解码格式不正确的表情符号十六进制字符串,如“`1f1e81f1f3`”?
【发布时间】:2017-12-17 16:04:06
【问题描述】:

假设有一个 emoji 字符的十六进制字符串,如“1f1e81f1f3”,它是一个 emoji 字符代码点的格式不正确的十六进制字符串,它应该是两个字符串,如1f1e81f1f3

我正在使用org.apache.commons.codec.binary.Hex 来解码十六进制字符串,但显然十六进制需要输入字符串的长度是偶数,所以我需要使十六进制字符串采用零填充样式,如“0@ 987654327@01f1f3".

目前,我只是将“1f”替换为“01f”,到目前为止还不错,但由于an emoji glyph may contains a sequence of unicode characters,所以

  • 简单地将“1f”替换为“01f”是否安全?
  • 如果不安全,如何安全/正确地解码此类十六进制字符串并恢复/翻译它们以更正表情符号字符/character_sequence?看来我需要实现一个自定义的 UTF16BE 解码器?

背景

这个表情符号的十六进制字符串是从“<span class="emoji emojiXXXXXXXXXX"></span>”字符串中剥离出来的,它是通过非官方的 HTTP API 从流行的 IM 软件中检索到的文本消息。

【问题讨论】:

  • 呃,显然不安全,对于标题中的示例十六进制字符串甚至都不安全,1f1f3 变成了01f01f3
  • 唯一安全的方法是在相应的样式表中查找emojiXXXXXXXXXX类的定义。
  • <span class="emoji emoji1f1e8"></span><span class="emoji emoji1f1f3"></span> 来源?然后,您可以获得格式正确的十六进制字符串,而不是 格式错误
  • @JosefZ,不,它们没有分开,一个表情符号只使用一个<span>,一个表情符号的所有字符序列在@的class属性内用十六进制字符串表示987654336@ 元素。我使用以下正则表达式来提取十六进制字符串:<span class=\"emoji emoji(\\p{XDigit}+)\"></span>.

标签: java unicode decode emoji


【解决方案1】:

最后我写了一个小函数来恢复表情符号。

基本流程:

  1. 创建一个指向十六进制字符串开头的指针。
  2. 从十六进制字符串的指针位置搜索,
    • 如果它以“1f”开头,则在“1f”之前填充三个零,将其存储到新的十六进制字符串中,然后将指针移至下一个第 5 位。否则,不进行零填充,将子字符串存储到新的十六进制字符串,并将指针移至下一个第 4 位。
    • 将新的十六进制字符串解码为字节数组。
    • 使用字节数组中的 UTF_32BE 或 UTF_16BE 字符编码创建新字符串。
  3. 循环到第 2 步,直到十六进制字符串结束。

有效,但并不完美,如果

  • emoji 字符序列的一个字符位于补字符中
  • 十六进制字符串不是以“1f”开头,或者十六进制字符串的长度不是5。

代码sn-p:

import java.util.*;
import java.util.regex.*;

import org.apache.commons.codec.*;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.*;

public static final Charset UTF_32BE = Charset.forName ("UTF-32BE");
public static final String REGEXP_FindTransformedEmojiHexString = "<span class=\"emoji emoji(\\p{XDigit}+)\"></span>";
public static final Pattern PATTERN_FindTransformedEmojiHexString = Pattern.compile (REGEXP_FindTransformedEmojiHexString, Pattern.CASE_INSENSITIVE);
public static String RestoreEmojiCharacters (String sContent)
{
        bMatched = true;
        String sEmojiHexString = matcher.group(1);

        Hex hex = new Hex (StandardCharsets.ISO_8859_1);
        try
        {
            for (int i=0; i<sEmojiHexString.length ();)
            {
                String sEmoji = null;
                Charset charset = null;
                String sSingleEmojiGlyphHexString = null;
                String sStartString = StringUtils.substring (sEmojiHexString, i, i+2);
                if (StringUtils.startsWithIgnoreCase (sStartString, "1f"))
                {
                    sSingleEmojiGlyphHexString = "000" + StringUtils.substring (sEmojiHexString, i, i+5);
                    i += 5;
                    charset = UTF_32BE;
                }
                else
                {
                    sSingleEmojiGlyphHexString = StringUtils.substring (sEmojiHexString, i, i+4);
                    i += 4;
                    charset = StandardCharsets.UTF_16BE;
                }
                byte[] arrayEmoji = null;
                arrayEmoji = (byte[])hex.decode (sSingleEmojiGlyphHexString);
                sEmoji = new String (arrayEmoji, charset);
                matcher.appendReplacement (sbReplace, sEmoji);
            }
        }
        catch (DecoderException e)
        {
            e.printStackTrace();
        }
    }
    matcher.appendTail (sbReplace);

    if (bMatched)
        sContent = sbReplace.toString ();

    return sContent;
}

【讨论】:

    猜你喜欢
    • 2019-07-13
    • 1970-01-01
    • 2020-11-11
    • 2018-08-21
    • 2022-07-08
    • 2021-03-07
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多