Java字符串与Unicode编码(码点、代码单元、基本多语言平面BMP、辅助平面、代理对)

Java字符串与Unicode编码

1. Unicode编码简介

Unicode是一个为世界上所有书写系统设计的字符编码标准。它旨在解决不同编码标准之间不兼容的问题,使得计算机能够处理和显示世界上几乎所有的字符。Unicode为每个字符分配了一个唯一的数字,称为"码点"(Code Point)。

2. Unicode码点与代码单元
  • 码点(Code Point):Unicode中的一个字符对应的唯一数字标识。
  • 代码单元(Code Unit):在特定编码方案中表示码点的基本单位。在Java中,char 数据类型通常用作Unicode代码单元。
3. Java中的char数据类型

在Java中,char 数据类型是一个16位的无符号整数,能够表示的范围是0到65535(即0x0000到0xFFFF)。这个范围足以覆盖Unicode基本多语言平面(BMP)中的所有字符,BMP包含了最常用的字符。然而,Unicode标准定义的字符远不止这些,还包括了许多辅助平面中的字符,如一些表情符号和特殊字符。

4. BMP与辅助平面
  • 基本多语言平面(BMP):包含了从U+0000到U+FFFF的字符,这个范围内的字符可以用一个16位的 char 值(即一个代码单元)来表示。
  • 辅助平面:包含了从U+10000到U+10FFFF的字符,这些字符无法直接用单个16位的 char 值表示。因此,Java使用一对 char 值(即两个代码单元)来表示这些字符,这种表示方式称为"代理对"(Surrogate Pair)。
5. 代理对

代理对是一种特殊的编码机制,用于在Java中表示辅助平面中的Unicode字符。每个代理对由两个 char 值组成,第一个值是高代理项(High Surrogate),范围从U+D800到U+DBFF;第二个值是低代理项(Low Surrogate),范围从U+DC00到U+DFFF。通过这两个值,可以唯一确定一个辅助平面中的字符。

6. Java字符串与Unicode

在Java中,字符串是由 char 值序列组成的,这意味着字符串可以包含BMP中的字符,也可以包含通过代理对表示的辅助平面中的字符。当处理包含辅助平面字符的字符串时,需要注意字符串的长度(即 char 值的数量)可能与字符的实际数量(即码点的数量)不同。

例如,一个包含单个表情符号(如😀)的字符串在Java中实际上由两个 char 值组成(即一个代理对),但通常我们认为这个字符串只包含一个字符。

java 复制代码
public class UnicodeExample {  
    public static void main(String[] args) {  
        // 创建一个包含单个表情符号的字符串  
        String smileyString = "😀";  
  
        // 使用String.length()方法获取字符串的长度(char值的数量)  
        int length = smileyString.length();  
        System.out.println("String length (char count): " + length); // 输出2,因为表情符号是一个代理对  
  
        // 使用String.codePointCount()方法获取字符串中的码点数量  
        int codePointCount = smileyString.codePointCount(0, smileyString.length());  
        System.out.println("Code point count: " + codePointCount); // 输出1,因为只有一个字符  
  
        // 使用String.charAt()方法访问字符串中的字符(这将返回代理对的一部分)  
        char firstChar = smileyString.charAt(0);  
        char secondChar = smileyString.charAt(1);  
        System.out.println("First char (surrogate high): " + (int) firstChar); // 输出代理对的高部分  
        System.out.println("Second char (surrogate low): " + (int) secondChar); // 输出代理对的低部分  
  
        // 使用String.codePointAt()方法获取完整的字符(码点)  
        int codePoint = smileyString.codePointAt(0);  
        System.out.println("Code point: " + codePoint); // 输出表情符号的码点  
  
        // 将码点转换回字符  
        char[] chars = Character.toChars(codePoint);  
        System.out.println("Character representation: " + new String(chars)); // 输出表情符号  
    }  
}

输出结果

String length (char count): 2

Code point count: 1

First char (surrogate high): 55357

Second char (surrogate low): 56832

Code point: 128512

Character representation: 😀

java 复制代码
// 使用String.codePointAt()方法获取完整的字符(码点)
int codePoint = smileyString.codePointAt(0);
System.out.println("Code point: " + codePoint); // 输出表情符号的码点
  • String.codePointAt(int index) 方法用于获取指定索引处的字符的码点。在这个例子中,index是 0,表示我们想要获取字符串中第一个字符的码点。
  • 由于表情符号(如 😀)是一个代理对,即由两个 char 值组成的字符,因此我们不能使用 charAt 方法来获取完整的字符。而 codePointAt 方法能够正确地返回整个字符的码点,无论它是否是一个代理对。
  • codePoint 变量存储了获取到的码点值,我们可以通过打印它来查看表情符号的码点。
java 复制代码
// 将码点转换回字符
char[] chars = Character.toChars(codePoint);
System.out.println("Character representation: " + new String(chars)); // 输出表情符号
  • Character.toChars(int codePoint) 方法用于将码点转换为对应的 char 数组。这个数组可能包含一个或两个 char 值,取决于码点是否表示一个代理对。
  • 在这个例子中,codePoint 是一个表情符号的码点,因此 toChars 方法会返回一个包含两个 char 值的数组,这两个值共同表示表情符号。
  • 我们通过将 chars 数组传递给 String 的构造函数来创建一个新的字符串,该字符串仅包含我们之前获取的码点对应的字符。然后,我们打印这个字符串来查看表情符号。
7. 注意事项
  • 当处理包含辅助平面字符的字符串时,使用String.length()方法将返回char值的数量,而不是码点的数量。如果需要获取码点的数量,应使用String.codePointCount(int beginIndex, int endIndex)方法。
  • 使用String.charAt(int index)方法访问字符串中的字符时,如果字符位于辅助平面,该方法将只返回代理对的一部分,而不是完整的字符。要获取完整的字符,应使用String.codePointAt(int index)方法。

Java中的字符串是由char值序列组成的,char数据类型采用UTF-16编码表示Unicode码点。BMP中的字符可以直接用一个char值表示,而辅助平面中的字符则需要通过代理对(即两个char值)来表示。在处理包含辅助平面字符的字符串时,需要注意char值的数量与码点数量之间的差异,并选择合适的方法来获取和处理这些字符。

相关推荐
NE_STOP12 分钟前
SpringBoot--简单入门
java·spring
hqxstudying39 分钟前
Java创建型模式---原型模式
java·开发语言·设计模式·代码规范
Dcs1 小时前
VSCode等多款主流 IDE 爆出安全漏洞!插件“伪装认证”可执行恶意命令!
java
保持学习ing1 小时前
day1--项目搭建and内容管理模块
java·数据库·后端·docker·虚拟机
京东云开发者1 小时前
Java的SPI机制详解
java
超级小忍2 小时前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
程序无bug2 小时前
Spring IoC注解式开发无敌详细(细节丰富)
java·后端
小莫分享2 小时前
Java Lombok 入门
java
程序无bug2 小时前
Spring 对于事务上的应用的详细说明
java·后端
食亨技术团队2 小时前
被忽略的 SAAS 生命线:操作日志有多重要
java·后端