杰瑞科技汇

Java如何将ASCII转为Unicode?

ASCII 是 Unicode 的一个子集。 这意味着任何一个 ASCII 字符(代码点在 0-127 之间)本身也是一个 Unicode 字符,你不需要“转换” ASCII 字符 成为 Unicode,因为它 已经是 Unicode 了。

Java如何将ASCII转为Unicode?-图1
(图片来源网络,侵删)

当人们说“ASCII 转 Unicode”时,他们真正想做的是以下两种事情之一:

  1. 获取字符串的 Unicode 代码点(Code Point)表示。
  2. 将字符串以 Unicode 编码(如 UTF-16 或 UTF-8)的形式存储或传输,即转换成字节数组。

下面我将针对这两种常见需求,提供详细的 Java 代码示例和解释。


获取字符串的 Unicode 代码点(Code Point)

这种方法用于获取字符串中每个字符的 Unicode 整数值,这对于字符分析、调试或理解字符串的内部表示非常有用。

示例 1:遍历字符并打印其 Unicode 值

String.charAt() 方法返回一个 char 类型,它可以表示大部分 Unicode 字符(基本多文种平面 BMP),但对于需要两个 char 表示的增补字符(Supplementary Characters)会返回一个“代理对”(Surrogate Pair),更可靠的方法是使用 String.codePointAt()

Java如何将ASCII转为Unicode?-图2
(图片来源网络,侵删)
public class AsciiToUnicodeExample {
    public static void main(String[] args) {
        // 一个包含标准ASCII字符和几个非ASCII(Unicode)字符的字符串
        String str = "Hello 世界! 😊";
        System.out.println("原始字符串: " + str);
        System.out.println("----------------------------------");
        // 方法1: 使用 codePointAt() 和 codePointCount()
        // 这是处理所有 Unicode 字符(包括增补字符)最可靠的方式
        System.out.println("--- 使用 codePointAt() 遍历 ---");
        int length = str.codePointCount(0, str.length());
        for (int i = 0; i < length; i++) {
            int codePoint = str.codePointAt(i);
            // 将代码点转换为char,用于打印字符本身
            // 注意:如果代码点是增补字符,这个转换会得到代理对
            char[] chars = Character.toChars(codePoint);
            System.out.println(
                "字符: " + new String(chars) + 
                ", Unicode 代码点 (十进制): " + codePoint + 
                ", Unicode 代码点 (十六进制): U+" + Integer.toHexString(codePoint).toUpperCase()
            );
            // 如果是增补字符,i 需要递增 2,否则递增 1
            i += Character.charCount(codePoint) - 1;
        }
        System.out.println("\n----------------------------------");
        // 方法2: 使用 charAt() (简单但不完全适用于所有Unicode字符)
        System.out.println("--- 使用 charAt() 遍历 (可能不完整) ---");
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            // char 的范围是 0-65535 (0xFFFF),无法直接表示所有代码点
            System.out.println(
                "字符: " + c + 
                ", Unicode 值 (十进制): " + (int) c + 
                ", Unicode 值 (十六进制): U+" + Integer.toHexString(c).toUpperCase()
            );
        }
    }
}

输出结果:

原始字符串: Hello 世界! 😊
----------------------------------
--- 使用 codePointAt() 遍历 ---
字符: H, Unicode 代码点 (十进制): 72, Unicode 代码点 (十六进制): U+48
字符: e, Unicode 代码点 (十进制): 101, Unicode 代码点 (十六进制): U+65
字符: l, Unicode 代码点 (十进制): 108, Unicode 代码点 (十六进制): U+6C
字符: l, Unicode 代码点 (十进制): 108, Unicode 代码点 (十六进制): U+6C
字符: o, Unicode 代码点 (十进制): 111, Unicode 代码点 (十六进制): U+6F
字符: 世, Unicode 代码点 (十进制): 19990, Unicode 代码点 (十六进制): U+4E16
字符: 界, Unicode 代码点 (十进制): 30028, Unicode 代码点 (十六进制): U+754C
字符: !, Unicode 代码点 (十进制): 33, Unicode 代码点 (十六进制): U+21
字符: 😊, Unicode 代码点 (十进制): 128578, Unicode 代码点 (十六进制): U+1F60A
----------------------------------
--- 使用 charAt() 遍历 (可能不完整) ---
字符: H, Unicode 值 (十进制): 72, Unicode 值 (十六进制): U+48
字符: e, Unicode 值 (十进制): 101, Unicode 值 (十六进制): U+65
字符: l, Unicode 值 (十进制): 108, Unicode 值 (十六进制): U+6C
字符: l, Unicode 值 (十进制): 108, Unicode 值 (十六进制): U+6C
字符: o, Unicode 值 (十进制): 111, Unicode 值 (十进制): 6F
字符: 世, Unicode 值 (十进制): 19990, Unicode 值 (十六进制): U+4E16
字符: 界, Unicode 值 (十进制): 30028, Unicode 值 (十六进制): U+754C
字符: !, Unicode 值 (十进制): 33, Unicode 值 (十六进制): U+21
字符: , Unicode 值 (十进制): 55357, Unicode 值 (十六进制): U+D83D
字符: , Unicode 值 (十进制): 56842, Unicode 值 (十六进制): U+DE0A

注意看 的区别:

  • codePointAt() 正确地识别出这是一个代码点 U+1F60A
  • charAt() 将其拆分为两个“代理字符”(Surrogate Characters)U+D83DU+DE0A,它们本身没有独立的语义,只是组合起来表示完整的 emoji。

将字符串编码为 Unicode 字节数组

这种方法通常用于将字符串序列化,以便存储在文件中、通过网络发送或与其他系统交互,Java 内部使用 UTF-16 编码,但你可以指定其他 Unicode 编码,如 UTF-8。

示例 2:使用 String.getBytes() 方法

String.getBytes(StandardCharsets charset) 是最推荐的方式,因为它明确指定了字符集,避免了平台默认编码带来的问题。

Java如何将ASCII转为Unicode?-图3
(图片来源网络,侵删)
import java.nio.charset.StandardCharsets;
public class AsciiToBytesExample {
    public static void main(String[] args) {
        String str = "Hello 世界!";
        System.out.println("原始字符串: " + str);
        System.out.println("字符串长度: " + str.length()); // 9
        // 1. 转换为 UTF-16 编码的字节数组 (Java内部默认编码)
        // 每个ASCII字符占2字节,中文字符也占2或4字节
        byte[] utf16Bytes = str.getBytes(StandardCharsets.UTF_16);
        System.out.println("\nUTF-16 编码的字节数组:");
        for (byte b : utf16Bytes) {
            System.out.printf("%02X ", b);
        }
        System.out.println("\nUTF-16 字节数组长度: " + utf16Bytes.length); // 通常是 2 * 字符数 + 2 (BOM)
        // 2. 转换为 UTF-8 编码的字节数组 (最通用、最节省空间的Unicode编码)
        // ASCII字符占1字节,中文字符通常占3字节
        byte[] utf8Bytes = str.getBytes(StandardCharsets.UTF_8);
        System.out.println("\nUTF-8 编码的字节数组:");
        for (byte b : utf8Bytes) {
            System.out.printf("%02X ", b);
        }
        System.out.println("\nUTF-8 字节数组长度: " + utf8Bytes.length); // 5*1 + 2*3 + 1 = 12
        // 3. 转换为平台默认编码的字节数组 (不推荐,因为结果在不同机器上可能不同)
        // byte[] defaultBytes = str.getBytes(); // 弃用方式,不推荐使用
    }
}

输出结果(取决于你的系统字节序,可能会有 BOM 标志的差异):

原始字符串: Hello 世界!
字符串长度: 9
UTF-16 编码的字节数组:
FE FF 00 48 00 65 00 6C 00 6C 00 6F 00 20 4E 16 75 4C 00 21 
UTF-16 字节数组长度: 20
UTF-8 编码的字节数组:
48 65 6C 6C 6F 20 E4 B8 96 E7 95 8C 21 
UTF-8 字节数组长度: 13
  • FE FF 是 UTF-16 的字节顺序标记(BOM),表示大端序。
  • 48 是 'H' 的 ASCII/UTF-8 值。
  • E4 B8 96 是 "世" 字的 UTF-8 编码,由3个字节组成。

总结与最佳实践

需求 推荐方法 说明
获取字符的 Unicode 代码点 str.codePointAt(index) 最准确,能正确处理所有 Unicode 字符,包括代理对。
将字符串转为字节数组(通用) str.getBytes(StandardCharsets.UTF_8) 强烈推荐,UTF-8 是互联网上最通用的编码,兼容 ASCII,且对非英文文本更节省空间。
将字符串转为字节数组(Java内部) str.getBytes(StandardCharsets.UTF_16) 如果你需要与 Java 内部表示或特定系统交互,注意它通常会产生比 UTF-8 更大的字节数组。
避免的错误做法 str.getBytes() 不指定字符集,使用平台默认编码,会导致程序在不同环境下行为不一致,是常见的 Bug 来源。

核心要点:

  1. ASCII 是 Unicode 的子集,ASCII 字符天然就是 Unicode 字符。
  2. “转换”通常指两种操作:获取代码点或编码为字节。
  3. 处理字符时,优先使用 codePointAt()codePointCount() 来确保完整性。
  4. 处理字节时,始终明确指定字符集,首选 StandardCharsets.UTF_8
分享:
扫描分享到社交APP
上一篇
下一篇