如何检查字节数组是否包含Java中的Unicode字符串?

Iai*_*ain 15 java regex unicode utf-8

给定一个UTF-8编码字符串或任意二进制数据的字节数组,可以在Java中使用哪些方法来确定它是什么?

该数组可以通过类似于以下的代码生成:

byte[] utf8 = "Hello World".getBytes("UTF-8");
Run Code Online (Sandbox Code Playgroud)

或者,它可能是由类似于以下代码生成的:

byte[] messageContent = new byte[256];
for (int i = 0; i < messageContent.length; i++) {
    messageContent[i] = (byte) i;
}
Run Code Online (Sandbox Code Playgroud)

关键是我们不知道数组包含什么但需要找出以填写以下函数:

public final String getString(final byte[] dataToProcess) {
    // Determine whether dataToProcess contains arbitrary data or a UTF-8 encoded string
    // If dataToProcess contains arbitrary data then we will BASE64 encode it and return.
    // If dataToProcess contains an encoded string then we will decode it and return.
}
Run Code Online (Sandbox Code Playgroud)

如何扩展到覆盖UTF-16或其他编码机制?

Mic*_*rdt 11

在所有情况下都不可能完全准确地做出决定,因为UTF-8编码的字符串一种任意二进制数据,但您可以查找UTF-8无效的字节序列.如果你发现任何,你知道它不是UTF-8.

如果数组足够大,这应该很好,因为这样的序列很可能出现在"随机"二进制数据中,如压缩数据或图像文件.

但是,有可能获得有效的UTF-8数据,这些数据解码为完全无意义的字符串(可能来自各种不同的脚本).短序列更可能发生这种情况.如果您担心这一点,您可能需要进行更仔细的分析,以查看字母字符是否都属于同一代码图表.然后,当您具有混合脚本的有效文本输入时,这可能会产生错误否定.


Ala*_*ore 5

这是从W3C网站使用UTF-8“二进制”正则表达式的方法

static boolean looksLikeUTF8(byte[] utf8) throws UnsupportedEncodingException 
{
  Pattern p = Pattern.compile("\\A(\n" +
    "  [\\x09\\x0A\\x0D\\x20-\\x7E]             # ASCII\\n" +
    "| [\\xC2-\\xDF][\\x80-\\xBF]               # non-overlong 2-byte\n" +
    "|  \\xE0[\\xA0-\\xBF][\\x80-\\xBF]         # excluding overlongs\n" +
    "| [\\xE1-\\xEC\\xEE\\xEF][\\x80-\\xBF]{2}  # straight 3-byte\n" +
    "|  \\xED[\\x80-\\x9F][\\x80-\\xBF]         # excluding surrogates\n" +
    "|  \\xF0[\\x90-\\xBF][\\x80-\\xBF]{2}      # planes 1-3\n" +
    "| [\\xF1-\\xF3][\\x80-\\xBF]{3}            # planes 4-15\n" +
    "|  \\xF4[\\x80-\\x8F][\\x80-\\xBF]{2}      # plane 16\n" +
    ")*\\z", Pattern.COMMENTS);

  String phonyString = new String(utf8, "ISO-8859-1");
  return p.matcher(phonyString).matches();
}
Run Code Online (Sandbox Code Playgroud)

如最初所写,正则表达式旨在用于字节数组,但是您不能使用Java的正则表达式来做到这一点。目标必须是实现CharSequence接口的对象(因此a char[]也不可用)。通过将byte[]ISO 解码为ISO-8859-1,可以创建一个String,其中每个字符串都char具有与原始数组中相应字节相同的无符号数字值。

正如其他人所指出的那样,这样的测试只能告诉你byte[] 可以包含UTF-8文本,而不是它。但是正则表达式非常详尽,原始二进制数据似乎不太可能越过它。甚至全零数组都不匹配,因为正则表达式从不匹配NUL。如果唯一的可能性是UTF-8和二进制,那么我将信任此测试。

而且,如果有的话,可以剥离UTF-8 BOM。否则,UTF-8 CharsetDecoder将把它当作文本传递。

UTF-16要困难得多,因为很少有字节序列总是无效的。我唯一能想到的就是那些缺少低代理伴侣的高代理角色,反之亦然。除此之外,您还需要一些上下文来确定给定序列是否有效。您可能会有西里尔字母,后跟中文表意文字,然后是笑脸装饰符号,但这绝对是有效的UTF-16。


Tho*_*sen -1

尝试解码它。如果没有收到任何错误,则它是有效的 UTF-8 字符串。

  • -1:事实错误。非文本二进制流可以被解码为有效的 UTF-8 字符串。如果UTF-8解码失败,则意味着你的二进制数据不是UTF-8;但如果 UTF-8 解码_没有_失败,则不能_保证_二进制数据_是_ UTF-8。 (2认同)