0

各种编程语言使用 2 字节char数据类型(不要与 C/C++ 混淆char,它只是一个字节),从中构造字符串。各种实用函数将尝试char在字符串中找到这样的 a,例如查找ein hello,或执行其他接受或返回chars 的操作(拆分、索引、替换、计算字符串中出现的字符数、长度……) .

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

一些程序/框架/操作系统(?)也将无法正确处理多char字符,而只会删除其中的第二个char并创建一个“损坏的”字符。

在处理字符串时,您不应该总是使用对代码点进行操作的方法吗?我错过了什么?恐怕有人必须向我解释为什么这个世界char在这似乎已经过时时继续使用。毕竟,char 的大小是否足够?我知道还有额外的“帮助”字符用于“升级”其他字符(将 o 变成 ö 等等)。这些是如何由char代码点迭代处理的?char如果您替换s 而不是“整个”代码点,是否有机会严重破坏您的字符串?

4

3 回答 3

1

总结一下问题的答案

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

的,存储一个Unicode字符是不够的,但是你不用担心,因为你不使用它来迭代

也可以看看

有关更多详细信息,请阅读下文


在处理字符串时,您不应该总是使用对代码点进行操作的方法吗?

几乎不应该这样做,因为与流行的看法相反,UTF-32 中的字符没有固定长度。UTF-32 只是单个码点的定长编码,但一个用户感知的字符可能由多个码点表示:

重要的是要认识到用户所认为的“字符”——一种语言书写系统的基本单位——可能不仅仅是一个单一的 Unicode 代码点。相反,该基本单元可能由多个 Unicode 代码点组成。为避免计算机使用术语字符时产生歧义,这称为用户感知字符。例如,“G”+grave-accent 是用户感知的字符:用户认为它是单个字符,但实际上由两个 Unicode 代码点表示。这些用户感知的字符由所谓的字素簇近似,可以通过编程方式确定。

字素簇边界对于排序规则、正则表达式、UI 交互、垂直文本的分割、首字母样式的边界识别以及计算文本中的“字符”位置非常重要。

Unicode 文本分割 - 字素簇边界

因此,我们应该只使用字形 AKA用户感知字符来代替,并且不能将段分成代码点。例如,人们通常会迭代字符串来查找特定字符,如果我们想查找稻穗 U+1F33E,那么它会意外匹配 ‍,因为该农民表情符号被编码为U+1F468 U+200D U+1F33E。然后该索引可用于将子字符串从其他内容获取,这可能会让用户大吃一惊。看看为什么表情符号字符像

于 2021-10-02T07:13:11.057 回答
0

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

  1. 仅支持 16 位字符 (UCS-2) 的语言和平台。这些不支持完整的 Unicode 范围(特别是最近添加的表情符号不在 BMP 范围内),但可以轻松地将 16 位用于与 Unicode 字符相关的所有内容。(您仍然可能会因为忘记您在字符串中的位置而搞砸,尽管通过始终确保您处于偶数字节偏移应该很容易避免此类错误。)

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

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

您的问题有点预设char并且int是公开的和明确定义的,但是许多语言并不容易让您访问具有 C 的多功能性/放弃的底层字节表示。

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

当我写这篇文章时,“正确”基本上意味着 UTF-8,但它也不是完全没有问题,尽管你需要代理等的那种 futzing 是不必要或有用的(或者,如果你从另一个方向看它, 正常情况现在有点笨拙,但通常是有充分理由的);剩下的问题通常是 Unicode 特有的(代码点的规范化、特定于语言环境的排序规则、渲染支持等)。也许后代也会对此嗤之以鼻。https://utf8everywhere.org/包含更多关于 UTF-8 如何至少保护我们免受 16 位世界中仍然常见的许多错误的信息。

于 2020-10-19T07:53:15.463 回答
0

注意:这是西方世界的观点,同时我们也有亚洲语言的历史和演变,我略过。在任何情况下,大多数字符集都转换为 Unicode

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

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

但是互联网和交换文件越来越普遍,因此在斯德哥尔摩制作的文件在德国或美国并不完全可读。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 的不同之处,它允许 31 位代码点。

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

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

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

就个人而言,我认为 Unix 方式是最好的一种,所以使用 UTF-8:保持 ASCII 兼容,并扩展。旧程序可以(透明地)处理 Unicode 字符,如果它们是在 Unicode 时代之前构建的(用于打印、存储、传输等,显然要获得字符的语义,它们需要能够识别 Unicode)。

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

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

于 2020-10-16T07:59:00.503 回答