2字节的char数据类型是否不足以处理Unicode字符串中的“字符”概念?

问题描述

各种编程语言都使用2字节的数据类型(不要与C / C ++的char混淆,后者只是一个字节),从中构造字符串。各种实用程序函数会尝试在字符串中找到这样的char,例如在char中寻找e,或执行其他接受或返回hello的操作(分割,indexof,replace,计算字符串中出现的字符数,长度,...)。

如果您深入研究,将会发现有关unicode代码点的信息。确实,Java(我也假设其他语言)允许您迭代这些代码点。但是这些似乎由char(4个字节)而不是int(2个字节)表示。很少有人看到有人使用代码点遍历字符串。由于这样的代码点可能跨越多个char(最多2个,对吗?char?),所以这不是执行字符串操作的最快方法,但它似乎是正确的方法

某些程序/框架/操作系统(?)也无法正确使用多个{int字符,而只能删除其中的第二个char并创建“损坏的”字符。

在处理字符串时,是否不总是使用对代码点进行操作的方法?我想念什么?恐怕有人不得不向我解释为什么这个世界似乎过时了为什么继续使用char。炭的大小毕竟足够吗?我知道还有其他“辅助”字符可用于“升级”其他字符(将o变成ö,以此类推)。 char代码点迭代如何处理这些问题?如果您替换char而不是“全部”代码点,是否没有机会严重破坏您的字符串?

解决方法

注意:这是西方世界的观点,与此同时,我们也了解了亚洲语言的历史和演变。无论如何,大多数字符集都是使用Unicode转换的

从历史上看,我们使用ASCII。实际上,我们还使用了其他字符编码,其中有些也没有区分大小写,但是后来ASCII成为事实上的标准(在使用拉丁脚本的西方计算机上)。 ASCII是不够的,因此有一些扩展:“代码页”,因此每个字符仍然是8位,但是人们可以选择要使用的字符集(以及要支持的语言)。

所有常用的现代操作系统都诞生于这样的时代。因此程序以此类约定,文件系统,API,文本文件等开头。

但是Internet和交换文件越来越普遍,因此在斯德哥尔摩产生的文件在德国或美国无法完全读取。 ISO对某些代码页(例如Latin-1等)进行了标准化,该代码页具有ASCII +一些共同的字符,并且某些部分根据编码而有所不同。 Windows使用Latin-1填充了未分配的空间(您看到它被描述为“ ANSI”)。但是亚洲文字也变得很重要(更好的计算机,因此我们可以将更多的字符用于日常使用,而不仅仅是用于排版)。

因此Unicode(和ISO)开始开发新标准。每个字符一套,与所有最常见的字符集兼容(因此您可以转换为Unicode,而后转换而不丢失信息:这确实有助于平稳过渡)。这样的新字符集应具有16位代码点[警告:这不再正确,但在第一个Unicode版本中是这样]。 (因此,我们有很多组合字符,“汉字统一”(将中文,日文和旧韩文字符合并为一个),以及对新韩文字符进行编码的特殊情况。

采用了这种版本的新语言,因此使用16位Unicode字符。

某些操作系统添加了具有这些16位字符的新API(Microsoft Windows在文件系统上以兼容的方式与长名称一起使用,因此旧计算机可以读取文件[只是短名称,并且具有8位字符])。这样,您就可以与旧程序兼容,但是新程序可以(不是强制性的)使用新的Unicode。

旧的语言和Unix等待着,试图获得兼容的和新的Unicode。

在1990年代初,这似乎是你的世界(就像你的问题一样)。

猜猜是什么? 16位是不够的。因此,新的(现在已经很旧)的Unicode添加了平面,并替代了平面。代理是保持分配的16位Unicode有效的一种技巧,但是允许(通过使用代理)创建0x10FFFF的字符。这与ISO有所不同,ISO允许使用31位代码点。

同时,还出现了UTF-8,因此与ASCII(以及许多库/操作系统使用的字符串结尾\0)兼容,但允许所有新的Unicode字符。 / p>

一些更现代的语言开始实现UTF-32(因此使用32位Unicode),一些旧的经过改编的语言(例如新的API),一些只是保留了代理,因此将“代码点”更改为“代码单元” 。 Python是例外之一:旧语言已转换为完整Unicode(现在在内部,它会选择最佳大小的8位,16位或32位),但是Python 3转换却非常痛苦(并且与旧代码不兼容) ,而且10年后,许多图书馆还没有准备就绪),因此我认为其他旧语言在尝试“升级”之前会三思而后行。

您的“问题”上的问题是,要获得16位(或32位)字符,您需要标记日。每个人都应该在同一天更新每个程序和每个操作系统。因此,您应该检查过去的旧代码并进行调整。或者有两组库,实际上所有操作系统都分成两部分:使用旧字符,或使用新字符。

我个人认为Unix方式是最好的方式,因此使用UTF-8:保持ASCII兼容并扩展。旧程序可以(透明地)处理Unicode字符,如果它们是在Unicode时代之前构建的(用于打印,存储,传输等,显然要获得字符的语义,则它们必须了解Unicode)。

因为有代码单元(因此一个Unicode代码点有时需要两个16位代码单元),并且要组合字符(不要假设仅由一个代码点来描述一个字形),以及变体选择器,表情符号变体/ tags等,迭代和修改单个字符没有多大意义。而且,我们不要忘记字体可以设计来自各种“字符”的字形。

因此,由于现有的程序和基础结构,对于所有语言而言,在全球范围内都很难使用UTF-32。既然UTF-8似乎占主导地位,我认为我们应该保留UTF-8:这样人们将使用Unicode库,或者只是透明地处理字节序列(也许只是合并,模板化等),也许是简单的搜索(对于ASCII,否则Unicode字符串必须规范化。)

,

是的,是的。这里大约有三种不同的情况。

  1. 仅支持16位字符(UCS-2)的语言和平台。这些不能支持完整的Unicode范围(值得注意的是,最近添加的表情符号不在BMP范围内),但是对于与Unicode字符相关的所有内容,可以轻松使用16位。 (尽管仍然可以通过确保自己处于偶数字节偏移量来避免此类错误,但是仍然可以通过丢失字符串内的位置来弄乱自己。)

  2. 支持UTF-16(包括替代)的语言和平台。如您所述,您必须知道单个代码点可以超过16位,并进行相应的调整。我敢肯定,如果您只想测试代理,那么实际上有很多Java应用程序实际上会替代代理。

  3. 将所有内容映射到某种内部表示形式的语言和平台。理想情况下,除非您特别需要去那里,否则甚至不应该有一种直接解决底层字节的方法。 (与Python给您str的方式进行比较,除非您专门将decode放入bytes中,反之亦然。如果您只是从Stack Overflow复制/粘贴代码而又不了解什么,那还是有可能搞砸的确实如此。)

您的问题有点以charint公开且定义明确为前提,但是许多语言都不容易让您使用C的通用性/放弃性来访问底层的字节表示形式。

至于“为什么”,Java基本上早于UTF-16,当然也早于UTF-8。与从一开始就正确将新模型改型为现有语言及其库相比,总是很困难。

当我写这篇文章时,“正确”基本上是指UTF-8,但这也不是完全没有问题的,尽管您不需要用代孕之类的烦恼是不必要的或有用的(或者,如果您从另一个方向,现在的正常情况有些困难,但通常是出于充分的理由);其余的问题通常是Unicode特有的(代码点的标准化,特定于语言环境的归类,渲染支持等)。也许子孙后代也会对此大笑。 https://utf8everywhere.org/包含了更多有关UTF-8如何至少使我们免受许多错误的困扰,这些错误在16位世界中仍然很常见。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...