【问题标题】:Check if a String is valid UTF-8 encoded in Java检查字符串是否是用 Java 编码的有效 UTF-8
【发布时间】:2011-07-08 09:03:14
【问题描述】:

如何检查字符串是否为有效的 UTF-8 格式?

【问题讨论】:

  • 你的意思是 byte[] 被有效编码?
  • 最简单的做法可能是对其进行解码并再次对其进行编码。检查你得到同样的东西。这在几乎所有情况下都是正确的。
  • @Peter 这并不总是有效,因为某些字符可以用不同的字节序列编码。两个字节序列都是正确的,并且编码相同的字符,但字节不同。
  • @Jesper,如果数据已经用 Java 编码,那将是相同的。这取决于 OP 真正想要测试的内容。顺便说一句,Java 中的 \0 字符被编码为两个字节。 ;)

标签: java encoding utf-8


【解决方案1】:

只能检查字节数据。如果你构造了一个字符串,那么它在内部已经是 UTF-16。

只有字节数组可以进行 UTF-8 编码。

这是 UTF-8 转换的常见情况。

String myString = "\u0048\u0065\u006C\u006C\u006F World";
System.out.println(myString);
byte[] myBytes = null;

try 
{
    myBytes = myString.getBytes("UTF-8");
} 
catch (UnsupportedEncodingException e)
{
    e.printStackTrace();
    System.exit(-1);
}

for (int i=0; i < myBytes.length; i++) {
    System.out.println(myBytes[i]);
}

如果您不知道字节数组的编码,juniversalchardet 是一个帮助您检测它的库。

【讨论】:

  • 澄清一下,严格来说,String 的实例不是 UTF-16 编码形式,因为它允许格式错误的代码单元序列(以孤立的代理代码单元的形式)。然而,它是一个 Unicode 16 位字符串。
  • 更严格地说,Java 字符串也不是真正的 Unicode 16 位字符串,因为它可以包含用于 UCS4(3 和 4 字节)字符的 surrogates
  • ICU4J 是另一个 Java 库,可以帮助您检测字节数组的编码:site.icu-project.org
  • Java 字符串使用基于 UTF-16 的接口。它在documentation 中这么说:“字符串表示 UTF-16 格式的字符串”。代理是 UTF-16 的一部分,而不是 UCS-2(UTF-16 的前身)。所以是的,Java 字符串是 16 位 Unicode 字符串,它们只是使用 UTF-16 而不是 UCS-2 作为 16 位编码。
  • UTF-16 不是每字符 16 位的 unicode 字符串表示。 UTF-16 是 unicode 字符串的可变字节表示......就像 UTF-8 是 unicode 字符串的可变字节表示一样。另一方面,UCS2 是字符串的固定 2 字节表示,但不涵盖所有 unicode 代码点。
【解决方案2】:

以下帖子摘自官方 Java 教程:https://docs.oracle.com/javase/tutorial/i18n/text/string.html

StringConverter 程序首先创建一个包含 Unicode 字符:

String original = new String("A" + "\u00ea" + "\u00f1" + "\u00fc" + "C");

打印时,名为 original 的字符串显示为:

AêñüC

要将 String 对象转换为 UTF-8,请调用 getBytes 方法并 指定适当的编码标识符作为参数。这 getBytes 方法返回一个 UTF-8 格式的字节数组。创建一个 来自非 Unicode 字节数组的字符串对象,调用字符串 带有编码参数的构造函数。使这些代码 调用包含在 try 块中,以防指定的编码是 不支持:

try {
    byte[] utf8Bytes = original.getBytes("UTF8");
    byte[] defaultBytes = original.getBytes();

    String roundTrip = new String(utf8Bytes, "UTF8");
    System.out.println("roundTrip = " + roundTrip);
    System.out.println();
    printBytes(utf8Bytes, "utf8Bytes");
    System.out.println();
    printBytes(defaultBytes, "defaultBytes");
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}

StringConverter 程序打印出 utf8Bytes 和 defaultBytes 数组来演示一个重要的点: 转换后的文本可能与源的长度不同 文本。一些 Unicode 字符转换为单个字节,其他字符转换为 字节对或三元组。 printBytes 方法通过调用源文件中定义的 byteToHex 方法来显示字节数组, UnicodeFormatter.java。这是 printBytes 方法:

public static void printBytes(byte[] array, String name) {
    for (int k = 0; k < array.length; k++) {
        System.out.println(name + "[" + k + "] = " + "0x" +
            UnicodeFormatter.byteToHex(array[k]));
    }
}

printBytes 方法的输出如下。注意只有第一个 最后一个字节,即 A 和 C 字符,在两个数组中都是相同的:

utf8Bytes[0] = 0x41
utf8Bytes[1] = 0xc3
utf8Bytes[2] = 0xaa
utf8Bytes[3] = 0xc3
utf8Bytes[4] = 0xb1
utf8Bytes[5] = 0xc3
utf8Bytes[6] = 0xbc
utf8Bytes[7] = 0x43
defaultBytes[0] = 0x41
defaultBytes[1] = 0xea
defaultBytes[2] = 0xf1
defaultBytes[3] = 0xfc
defaultBytes[4] = 0x43

【讨论】:

    猜你喜欢
    • 2010-12-01
    • 2016-07-18
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多