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值的数量与码点数量之间的差异,并选择合适的方法来获取和处理这些字符。

相关推荐
星河梦瑾31 分钟前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富35 分钟前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想36 分钟前
JMeter 使用详解
java·jmeter
言、雲39 分钟前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇1 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
Yvemil71 小时前
《开启微服务之旅:Spring Boot 从入门到实践》(三)
java
Anna。。1 小时前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea
.生产的驴2 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
爱上语文2 小时前
宠物管理系统:Dao层
java·开发语言·宠物
王ASC2 小时前
SpringMVC的URL组成,以及URI中对/斜杠的处理,解决IllegalStateException: Ambiguous mapping
java·mvc·springboot·web