首页 > 解决方案 > 验证字符串是用 Java 编码的 UTF-8

问题描述

有很多方法可以检查字符串是否为 UTF-8 编码,例如:

public static boolean isUTF8(String s){
    try{
        byte[]bytes = s.getBytes("UTF-8");
    }catch(UnsupportedEncodingException e){
        e.printStackTrace();
        System.exit(-1);
    }
    return true;
}

的文档java.lang.String#getBytes(java.nio.charset.Charset)说:

此方法始终使用此字符集的默认替换字节数组替换格式错误的输入和不可映射的字符序列。

  1. 它总是返回正确的 UTF-8 字节是否正确?
  2. 对对象执行此类检查是否有意义String?它不会总是true作为 String 对象返回吗?
  3. 据我了解,此类检查应在字节上执行,而不是在String对象上:
public static final boolean isUTF8(final byte[] inputBytes) {
    final String converted = new String(inputBytes, StandardCharsets.UTF_8);
    final byte[] outputBytes = converted.getBytes(StandardCharsets.UTF_8);
    return Arrays.equals(inputBytes, outputBytes);
}

但在这种情况下,我不确定我应该从哪里拿走这些butes,因为直接从String对象中获取它是不正确的。

标签: javastringencodingutf-8utf-16

解决方案


它总是返回正确的 UTF-8 字节是否正确?

是的。

对 String 对象执行此类检查是否有意义?由于 String 对象已经编码,它不会总是返回 true 吗?

Java 字符串使用以 UTF-16 编码的 Unicode 字符。由于 UTF-16 使用代理项对,任何未配对的代理项都是无效的,因此 Java 字符串可以包含无效char序列。

Java 字符串还可以包含在 Unicode 中未分配的字符。

这意味着在 Java 上执行验证String是有意义的,尽管很少这样做。

据我了解,此类检查应在字节上执行,而不是在字符串对象上。

根据字节的字符集,没有什么要验证的,例如字符集 CP437 映射所有 256 字节值,因此它不会无效。

UTF-8 可能无效,因此验证字节很有用是正确的。


正如javadoc所说,getBytes(Charset)总是用字符集的默认替换字节替换格式错误的输入和不可映射的字符序列。

那是因为它这样做:

CharsetEncoder encoder = charset.newEncoder()
        .onMalformedInput(CodingErrorAction.REPLACE)
        .onUnmappableCharacter(CodingErrorAction.REPLACE);

如果您想获取字节,但在格式错误的输入和不可映射的字符序列上失败,请CodingErrorAction.REPORT改用。因为这实际上是默认值,所以不要调用这两种onXxx()方法。

例子

String s = "\uD800"; // unpaired surrogate
System.out.println(Arrays.toString(s.getBytes(StandardCharsets.UTF_8)));

打印[63]的是 a ?,即未配对的代理是格式错误的输入,因此它被替换为替换字节。

String s = "\uD800"; // unpaired surrogate

CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();
ByteBuffer encoded = encoder.encode(CharBuffer.wrap(s.toCharArray()));
byte[] bytes = new byte[encoded.remaining()];
encoded.get(bytes);

System.out.println(Arrays.toString(bytes));

这是MalformedInputException: Input length = 1因为默认的格式错误输入操作是REPORT.


推荐阅读