Java Character源码剖析

Character类除了封装了一个char外,还封装了Unicode字符级别的各种操作,是Java文本处理的基础。下面结合源码分析Character的贡献。

Unicode

也许你没听过Unicode,但应该见过UTF-8。UTF-8(8-bit Unicode Transformation Format)是一种常用的Unicode字符编码方案之一。它使用变长编码方式,将Unicode码点编码成1至4个字节的序列。UTF-8编码保证了对ASCII字符的向后兼容性,因此在处理纯英文文本时,其存储效率与ASCII编码相同。

而Unicode是一种字符编码标准,它为世界上几乎所有的字符分配了一个唯一的数字标识符。它旨在为文字的表示提供一种统一的方式,使得不同国家和语言的字符都能被正确地编码和解码。

在字符编码中,有两个重要的概念:代码点(code point)和代码单元(code unit)。

代码点是Unicode标准中给每个字符分配的唯一整数值。它对应于一个字符的抽象概念,表示文本中的一个字符。Unicode的代码点范围从U+0000到U+10FFFF。每个代码点都有一个唯一的编号,可以用十六进制形式表示,例如U+0041表示字符'A'。

代码单元是计算机中存储和处理字符时使用的最小单位。在Unicode中,代码单元的大小可以是8位(1个字节)或16位(2个字节)。在Java中,字符是使用Unicode编码表示的。Java的char类型是16位无符号整数(即UTF-16) ,用于表示一个Unicode字符。因此,Java中的字符串实际上是由一系列Unicode字符组成的。

然而,Unicode中的某些字符需要用多个代码单元来表示,这种情况下被称为代理对(surrogate pair)。代理对由一个高位代理项(High Surrogate,范围U+D800至U+DBFF)和一个低位代理项(Low Surrogate,范围U+DC00至U+DFFF)组成,它们一起表示一个字符。通过组合高位和低位代理项可以得到完整的代码点。

比如 ☺️ 的码点U+1F60A可以通过代理对的方式表示:

  1. 计算出该码点在辅助平面中的偏移量:U+1F60A - U+10000 = 0xF60A
  2. 将偏移量拆分为高位和低位代理项:
    • 高位代理项:0xD83D (U+D800 + 0xF60A >> 10)
    • 低位代理项:0xDE0A (U+DC00 + 0xF60A & 0x3FF)
  3. 使用这两个代理项来构成代理对,从而表示 ☺️。
int codePoint = 0x1F60A;
char[] surrogatePair = Character.toChars(codePoint);
System.out.println("UTF-16 编码: " + new String(surrogatePair));

检查代码点和字符

Character类中有很多相关静态方法,以下是对code point和char的检查

//判断一个int是不是一个有效的代码点,小于等于0x10FFFF的为有效,大于的为无效
public static boolean isValidCodePoint(int codePoint)
//判断一个int是不是BMP字符,小于等于OxFFFF的为BMP字符,大于的不是
public static boolean isBmpCodePoint(int codePoint)
//判断一个int是不是增补字符,0x010000~0X10FFFF为增补字符
public static boolean isSupplementaryCodePoint(int codePoint)
//判断char是否是高代理项,0xD800~0xDBFF为高代理项
public static boolean isHighSurrogate(char ch)
//判断char是否为低代理项,0xDC00~0xDFFF为低代理项
public static boolean isLowSurrogate(char ch)
//判断char是否为代理项,char为低代理项或高代理项,则返回true
public static boolean isSurrogate(char ch)
//判断两个字符high和low是否分别为高代理项和低代理项
public static boolean isSurrogatePair(char high, char low)
//判断一个代码点由几个char组成,增补字符返回2,BMP字符返回1
public static int charCount(int codePoint)

代码点和字符的互转

之前仅针对int和char之间的转换相信大家都很熟悉,就是参照ASCII码

从代码点到字符的转换:

int codePoint = 65; // 代码点(Unicode码点)
char c = (char) codePoint; // 将代码点转换为字符
System.out.println(c); // 输出字符 'A'

从字符到代码点的转换:

char c = 'A'; // 字符
int codePoint = c; // 将字符转换为代码点(Unicode码点)
System.out.println(codePoint); // 输出代码点 65

而有了低代理项和高代理项后,需要用复杂的公式转换。这个公式的基本思想是将高代理项和低代理项分别减去一个偏移量(0xD8000xDC00),然后将它们组合起来生成代码点。

public static int toCodePoint(char high, char low) {return ((high - 0xD800) << 10) + (low - 0xDC00) + 0x10000;
}

下面是其他的处理函数

//根据高代理项high和低代理项1ow生成代码点,这个转换有个公式,这个方法封装了这个公式
public static int toCodePoint(char high, char low)
//根据代码点生成char数组,即UTF-16表示,如果code point为BMP字符,则返回的char
//数组长度为1,如果为增补字符,长度为2,char[0]为高代理项,char[1]为低代理项
public static char[] toChars(int codePoint)
//将代码点转换为char数组,与上面方法类似,只是结果存入指定数组dst的指定位置index
public static int toChars(int codePoint, char[] dst, int dstIndex)
//对增补字符code point,生成低代理项
public static char lowSurrogate(int codePoint)
//对增补字符code point,生成高代理项
public static char highSurrogate(int codePoint)

Unicode字符属性

Unicode在给每个字符分配一个编号之外,还分配了一些属性Unicode给每个字符分配了一个类型,这个类型是非常重要的,很多其他检查和操作都是基于这个类型的。getType方法的参数可以是int类型的code point,也可以是char类型。char类型只能处理BMP字符,而int类型可以处理所有字符。Character类中很多方法都是既可以接受int类型,也可以接受char类型。

//获取字符类型
public static int getType(int codePoint)
public static int getType(char ch)

根据这个类型属性,可以获得字符的信息

//检查字符是否在Unicode中被定义:
public static boolean isDefined(int codePoint)
//检查是否为字母:
public static boolean isLetter(int codePoint)
//检查是否为字母或数字:
public static boolean isLetterOrDigit(int codePoint)
//检查是否为字母(Alphabetic):
public static boolean isAlphabetic(int codePoint)
//检查是否为空格字符:
public static boolean isSpaceChar(int codePoint)
//匹配实际产生空格效果的字符,如Tab控制键't'。更常用的检查空格的方法:
public static boolean isWhitespace(int codePoint)
//检查是否为小写字符:
public static boolean isLowerCase(int codePoint)
//检查是否为大写字符:
public static boolean isUpperCase(int codePoint)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/671129.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux的进程信号

注意&#xff1a;首先需要提醒一个事情&#xff0c;本节提及的进程信号和下节的信号量没有任何关系&#xff0c;请您区分对待。 1.信号概念 1.1.生活中的信号 我们在生活中通过体验现实&#xff0c;记忆了一些信号和对应的处理动作&#xff0c;这意味着信号有以下相关的特点&…

ROS笔记二:launch

目录 launch node标签 参数 参数服务器 节点分组 launch launch文件是一种可以可实现多节点启动和参数配置的xml文件,launch文件用于启动和配置ROS节点、参数和其他相关组件。launch文件通常使用XML格式编写&#xff0c;其主要目的是方便地启动ROS节点和设置节点之间的连…

Kuberntes权威指南

一、目录 二、Kubernetes入门 三、Kubernetes核心原理 四、Kubernetes开发指南 五、Kubernetes运维指南 六、Kubernetes高级案例进阶 七、Kubernetes源码导读

20240206三次握手四次挥手

TCP和UDP异同点 相同点&#xff1a;同属于传输层的协议 不同点&#xff1a; TCP ----> 稳定 1> 提供面向连接的&#xff0c;可靠的数据传输服务 2> 传输过程中&#xff0c;数据无误、数据无丢失、数据无失序、数据无重复 1、TCP会给每个数据包编上编号&#xff…

分享71个节日PPT,总有一款适合您

分享71个节日PPT&#xff0c;总有一款适合您 71个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1v4_fHplsf_hOJQbNPVUudg?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

区块链金融科技:技术融合与挑战应对【文末送书-16】

文章目录 前言一.区块链与金融科技的融合&#xff1a;革新金融格局的技术之光1.1区块链技术简介1.2 区块链在金融科技中的应用 二.智能合约2.1 去中心化金融&#xff08;DeFi&#xff09;2.2区块链对金融科技的影响2.3数据安全性 三.区块链与金融科技【文末送书-16】3.1 粉丝福…

leetcode 算法 67.二进制求和(python版)

需求 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 示例 1&#xff1a; 输入:a “11”, b “1” 输出&#xff1a;“100” 示例 2&#xff1a; 输入&#xff1a;a “1010”, b “1011” 输出&#xff1a;“10101” 代码 class Solution…

安全SCDN有什么作用

当前网络安全形势日益严峻&#xff0c;网络攻击事件频发&#xff0c;攻击手段不断升级&#xff0c;给企业和个人带来了严重的安全威胁。在这种背景下&#xff0c;安全SCDN作为一种网络安全解决方案&#xff0c;受到了广泛的关注。那么&#xff0c;安全SCDN真的可以应对网络攻击…

【leetcode题解C++】77.组合 and 216.组合总和III and 17.电话号码的字母组合

77. 组合 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ] 示例 2&#xff1a; 输入&#xff1a…

在 CentOS 7上使用 Apache 和 mod_wsgi 部署 Django 应用的方法

简介 Django 是一个强大的 Web 框架&#xff0c;可以帮助您快速启动 Python 应用程序或网站。Django 包括一个简化的开发服务器&#xff0c;用于在本地测试代码&#xff0c;但对于任何与生产相关的事情&#xff0c;都需要一个更安全和功能强大的 Web 服务器。 在本指南中&…

【Vitis】基于C++函数开发组件的步骤

目录 基本步骤 关键领域 • 硬件接口&#xff1a; 任务级并行度&#xff1a; 存储器架构&#xff1a; 微观级别的最优化&#xff1a; 基本步骤 1. 基于 设计原则 建立算法架构。 2. &#xff08;C 语言仿真&#xff09; 利用 C/C 语言测试激励文件验证 C/C 代码的逻辑。…

两个线程实现同步代码示例

#include<myhead.h>//1、定义无名信号量 sem_t sem;//定义生产者线程 void *task1(void *arg) {int num 5;while(num--){sleep(1);printf("我生产了一辆汽车\n");//4、释放资源sem_post(&sem);}//退出线程pthread_exit(NULL); }//定义消费者线程 void *ta…

win10没有调节亮度选项怎么办?

最近新装了win10&#xff0c;装机后”设置“-”显示“里面没有可以调节亮度的地方&#xff0c;这里记录一下解决方案。 解决方案 按WinX键&#xff0c;选择设备管理器&#xff0c;点击”显示适配器“&#xff0c;我这里默认是只有”Microsoft 基本显示适配器“&#xff0c;没有…

c++入门学习④——对象的初始化和清理

目录 对象的初始化和清理&#xff1a; why? 如何进行初始化和清理呢&#xff1f; 使用构造函数和析构函数​编辑 构造函数语法: 析构函数语法: 构造函数的分类&#xff1a; 两种分类方式&#xff1a; 三种调用方法&#xff1a; 括号法&#xff08;默认构造函数调用&…

UE中对象创建方法示例和类的理解

对象创建方法示例集 创建Actor示例 //创建一个护甲道具 AProp* armor GetWorld()->SpawnActor<AProp>(pos, rotator); 创建Component示例 UCapsuleComponent* CapsuleComponent CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleComponent&qu…

【C#】创建Json文件并根据dll路径获取

创建Json文件 更改属性 【代码】根据dll路径获取 Assembly assembly Assembly.GetExecutingAssembly(); string assemblyPath assembly.Location; string relativeDllPath System.IO.Path.Combine(System.IO.Path.GetDirectoryName(assemblyPath), "Json\\test.json&q…

liunx服务器下vim无法:wq解决方案

当你vim某一个文件是&#xff0c;由于其他人在操作&#xff0c;或者上次操作中断&#xff0c;造成的 解决方案&#xff0c;不要&#xff0c;vim -r /etc/****&#xff0c;不然你会得到 正确方案 然后在&#xff0c;直接sudo vim /ect/xxx&#xff0c;还出现第一幅图就直接选…

LabVIEW高精度微小电容测量

LabVIEW高精度微小电容测量 在电子工程和科研领域&#xff0c;精确测量微小电容值是一项有一定要求的任务&#xff0c;尤其在涉及到高精度和低成本时。设计了一种基于LabVIEW高精度微小电容测量系统&#xff0c;旨在提供一个既经济又高效的解决方案。 该系统的核心在于使用FD…

陪诊系统|陪诊小程序|陪诊服务让就医更容易

陪诊系统已经出现了好几年。尤其是这两年&#xff0c;它得到了人们的广泛认可。陪诊行业的快速发展主要是因为人们对这个行业的需求非常大。目前&#xff0c;我国面临着严重的老龄化问题&#xff0c;生活节奏也越来越快&#xff0c;有时候无法亲自陪伴在老人的身边。陪诊工作人…

openGauss学习笔记-215 openGauss性能调优-确定性能调优范围-性能日志

文章目录 openGauss学习笔记-215 openGauss性能调优-确定性能调优范围-性能日志215.1 性能日志概述215.2 性能日志收集的配置参数 openGauss学习笔记-215 openGauss性能调优-确定性能调优范围-性能日志 215.1 性能日志概述 性能日志主要关注外部资源的访问性能问题。 性能日…