Java中的UTF-16到ASCII转换

His*_*His 4 java ascii utf-16

一直忽略它,我目前正在强迫自己更多地了解Java中的unicode.关于将UTF-16字符串转换为8位ASCII,我需要做一些练习.有人可以请教我如何用Java做到这一点?我知道你不能用ASCII表示所有可能的unicode值,所以在这种情况下我想要只是添加超过0xFF的代码(不好的数据也应该静默添加).

谢谢!

Gun*_*r47 13

您可以使用java.nio来获得简单的解决方案:

// first encode the utf-16 string as a ByteBuffer
ByteBuffer bb = Charset.forName("utf-16").encode(CharBuffer.wrap(utf16str));
// then decode those bytes as US-ASCII
CharBuffer ascii = Charset.forName("US-ASCII").decode(bb);
Run Code Online (Sandbox Code Playgroud)


Ste*_*n C 8

这个怎么样:

String input = ... // my UTF-16 string
StringBuilder sb = new StringBuilder(input.length());
for (int i = 0; i < input.length(); i++) {
    char ch = input.charAt(i);
    if (ch <= 0xFF) {
        sb.append(ch);
    }
}

byte[] ascii = sb.toString().getBytes("ISO-8859-1"); // aka LATIN-1
Run Code Online (Sandbox Code Playgroud)

这可能不是对大字符串进行此转换的最有效方法,因为我们将字符复制两次.但是,它具有直截了当的优点.

顺便说一句,严格来说,没有像8位ASCII这样的字符集.ASCII是一个7位字符集.LATIN-1是最接近"8位ASCII"字符集的东西(Unicode的块0相当于LATIN-1),所以我假设这就是你的意思.

编辑:根据问题的更新,解决方案更简单:

String input = ... // my UTF-16 string
byte[] ascii = new byte[input.length()];
for (int i = 0; i < input.length(); i++) {
    ascii[i] = (byte) input.charAt(i);
}
Run Code Online (Sandbox Code Playgroud)

该解决方案更有效.由于我们现在知道要多少字节,我们可以预先分配字节数组并复制(截断的)字符,而不使用StringBuilder作为中间缓冲区.

但是,我不相信用这种方式处理坏数据是明智的.

编辑2:还有一个模糊的"陷阱".Unicode实际上将代码点(字符)定义为"大致21位"值... 0x000000到0x10FFFF ...并使用代理来表示代码> 0x00FFFF.换句话说,Unicode代码点> 0x00FFFF实际上以UTF-16表示为两个"字符".无论是我的答案还是其他任何一个都没有考虑到这一点(诚然是深奥的).事实上,在Java中处理代码点> 0x00FFFF一般来说相当棘手.这源于'char'是16位类型而String是根据'char'定义的事实.

编辑3:对于处理不转换为ASCII的意外字符,可能更合理的解决方案是用标准替换字符替换它们:

String input = ... // my UTF-16 string
byte[] ascii = new byte[input.length()];
for (int i = 0; i < input.length(); i++) {
    char ch = input.charAt(i);
    ascii[i] = (ch <= 0xFF) ? (byte) ch : (byte) '?';
}
Run Code Online (Sandbox Code Playgroud)