Java 如何解码表情符号不适形成的十六进制字符串,如`1f1e81f1f3`";?
假设有一个十六进制的表情符号字符串,比如“Java 如何解码表情符号不适形成的十六进制字符串,如`1f1e81f1f3`";?,java,unicode,decode,emoji,Java,Unicode,Decode,Emoji,假设有一个十六进制的表情符号字符串,比如“1f1e81f1f3”,它是一个表情符号的代码点的不合适的十六进制字符串,应该是两个字符串,比如1f1e81f1f3 我用它来解码十六进制字符串,但显然十六进制需要输入字符串的长度是均匀的,所以我需要将十六进制字符串设置为零填充样式,如“01f1e801f1f3” 目前,我只是简单地将“1f”替换为“01f”,到目前为止还不错,但从那时起,到现在为止 简单地将“1f”替换为“01f”安全吗 如果不安全,如何安全/正确地解码这些十六进制字符串,并将其还原
1f1e81f1f3
”,它是一个表情符号的代码点的不合适的十六进制字符串,应该是两个字符串,比如1f1e8
1f1f3
我用它来解码十六进制字符串,但显然十六进制需要输入字符串的长度是均匀的,所以我需要将十六进制字符串设置为零填充样式,如“01f1e8
01f1f3
”
目前,我只是简单地将“1f”替换为“01f”,到目前为止还不错,但从那时起,到现在为止
- 简单地将“1f”替换为“01f”安全吗
- 如果不安全,如何安全/正确地解码这些十六进制字符串,并将其还原/翻译为正确的表情符号/字符序列?似乎我需要实现一个定制的UTF16BE解码器
这个表情符号的十六进制字符串是从“
”字符串中剥离出来的,它是一条通过非官方HTTP API从流行IM软件中检索到的文本消息。我最后编写了一个小函数来恢复表情符号
基本程序:
- 如果它以“
”开头,则在“1f
”之前填入三个零,将其存储到新的十六进制字符串中,然后将指针移到下一个第5位。否则,不进行零填充,将子字符串存储到新的十六进制字符串,并将指针步移到下一个第四位置1f
- 将新的十六进制字符串解码为字节数组
- 使用字节数组中的UTF_32BE或UTF_16BE字符编码创建新字符串
- 表情符号字符序列的一个字符位于补充字符中
- 及
- 它的十六进制字符串不以“
”开头,或者它的十六进制字符串的长度不是51f
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;
}
import java.util.*;
导入java.util.regex.*;
导入org.apache.commons.codec.*;
导入org.apache.commons.codec.binary.Hex;
导入org.apache.commons.lang3.*;
公共静态最终字符集UTF_32BE=Charset.forName(“UTF-32BE”);
公共静态最终字符串REGEXP_findttransformedemojihexstring=“”;
公共静态最终模式Pattern\u findttransformedemojihexstring=Pattern.compile(REGEXP\u findttransformedemojihexstring,Pattern.CASE\u不区分大小写);
公共静态字符串RestoreEmojiCharacters(字符串内容)
{
b匹配=真;
String sEmojiHexString=matcher.group(1);
十六进制=新十六进制(标准字符集ISO_8859_1);
尝试
{
对于(inti=0;ii),我最终编写了一个小函数来恢复表情符号
基本程序:
创建一个指向十六进制字符串开头的指针
从十六进制字符串的指针位置进行搜索,
- 如果它以“
1f
”开头,则在“1f
”之前填充三个零,将其存储到一个新的十六进制字符串,然后指针步进到下一个第5位。否则,不进行零填充,将子字符串存储到一个新的十六进制字符串,并将指针步进到下一个第4位
- 将新的十六进制字符串解码为字节数组
- 使用字节数组中的UTF_32BE或UTF_16BE字符编码创建新字符串
循环到步骤2,直到十六进制字符串结束
它可以工作,但并不完美,如果
- 表情符号字符序列的一个字符位于补充字符中
- 及
- 它的十六进制字符串不以“
1f
”开头,或者它的十六进制字符串的长度不是5
代码段:
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;
}
import java.util.*;
导入java.util.regex.*;
导入org.apache.commons.codec.*;
导入org.apache.commons.codec.binary.Hex;
导入org.apache.commons.lang3.*;
公共静态最终字符集UTF_32BE=Charset.forName(“UTF-32BE”);
公共静态最终字符串REGEXP_findttransformedemojihexstring=“”;
公共静态最终模式Pattern\u findttransformedemojihexstring=Pattern.compile(REGEXP\u findttransformedemojihexstring,Pattern.CASE\u不区分大小写);
公共静态字符串RestoreEmojiCharacters(字符串内容)
{
b匹配=真;
String sEmojiHexString=matcher.group(1);
十六进制=新十六进制(标准字符集ISO_8859_1);
尝试
{
对于(int i=0;iuh,显然它不安全,标题中的示例十六进制字符串甚至不安全,1f1f3
变成01f01f3
。唯一安全的方法是在相应的样式表中查找emojixxxxxxxxx
类的定义。
origin?然后,您可以得到格式良好的十六进制字符串而不是格式错误的符号。@JosefZ,不,它们没有分开,一个表情符号只使用一个
,相反,表情符号的所有字符序列都在span
元素的class
属性中以十六进制字符串表示。我使用以下正则表达式提取十六进制字符串:
。嗯,很明显显然,这是不安全的,对于标题中的示例十六进制字符串,1f1f3
变为01f01f3
。唯一安全的方法是在相应的样式表中查找emojixxxxxxxxx
类的定义。
来源?然后,您可以得到格式良好的十六进制字符串而不是格式错误的符号。@JosefZ,不,它们没有分开,一个表情符号只使用一个
,相反,表情符号的所有字符序列都在span
元素的class
属性内以十六进制字符串表示。我使用以下正则表达式提取十六进制字符串:
。