使用Windows API处理Unicode字符串

Unicode string handling using Windows API

本文关键字:Unicode 字符串 处理 API Windows 使用      更新时间:2023-10-16

我一直认为Unicode字符串处理是某种黑暗艺术。但是,我看到Windows API有比较Unicode字符串的函数。这是否意味着编写一个Unicode字符串类来执行简单的操作(如排序、相等比较和从文件中提取)实际上是可行的?或者在这些函数的使用中存在隐藏的陷阱,使得它实际上是一个非常糟糕的主意?我只是看了看像ICU这样的库,与Windows API支持的Unicode字符串类相比,它们看起来令人难以置信的过于复杂,后者与标准字符串类非常相似。

这是否意味着实际上可以编写一个Unicode字符串类,可以执行简单的操作,如排序、相等比较和从文件中提取?

是的。c#、Java、。net、Python(列表还在继续)都有Unicode字符串作为基本类型,甚至C/c++的库(如ICU)都有。

或者在使用这些函数时是否存在隐藏的陷阱,使得它实际上是一个非常糟糕的主意?

是的,有陷阱。对"坏主意"的肯定要少一些。让我们以您发布的示例为例:"排序、相等比较和从文件中提取"。

  • 从文件中提取:这个任务很容易,如果你知道你的文件是在什么字符编码。大多数语言都提供了一些读取文件的方法,并将其从字节转换为"unicode"。语言的类型。(例如,在python中,data = file_handle.read()从文件中读取,然后data.decode(encoding_my_file_uses)给我一个unicode字符串对象。(或Python 3中的str)

  • 相等比较:事情在这里变得有点棘手。Unicode的基本构建块是"代码点"。Unicode字符串只不过是一个代码点序列。但是,Unicode包含与前一个字符组合的重音码点,但它也有一些重音"预先组合"的码点。可能是2个代码点(e +精确)或1个代码点。如果我有两个字符串,一个是2码点版本,一个是1码点版本,它们是一样的吗?答案可能取决于你想要什么。同样,如果您有一个具有多个重音的字符(在越南语中很常见),则重音可以按任何顺序排列。

    钥匙吗?你必须意识到你想要什么样的平等。不区分大小写的相等操作使其更加有趣,因为不同的语言对于字母的大写或小写版本有不同的想法。也就是说,Unicode定义并提供了以特定顺序获取代码点的方法(一种使字符串规范化的方法),从而使这些事情变得更容易。像ICU这样的库,甚至一些语言的标准库,已经在各种函数中为你实现了这些。

  • 排序:排序实际上很像相等。你需要知道你真正想要的是什么。排序顺序可能与语言有关。对我来说,ä和a都是"a"。应该排序在一起,但这并不总是正确的。(有些语言把ä放在z后面。)另一个例子:丵排序到哪里?作为一个说英语的人,我没有一个好的答案,除了"在其他事情之前或之后"。最简单的排序是按代码点顺序排序,但对大多数人来说没有任何有用的东西。

    这里的答案是类似的:Unicode定义了如何做到这一点的方法,并且各种库(如ICU)实现了这些方法。

例如,

ICU应该能够以一种相对简单的方式为您完成所有这些工作,. net也包含了相应的方法。虽然上面的内容看起来很复杂,但我发现我写过的大多数代码都没有执行需要上面大部分内容的操作。大多数情况下,您只是将字符串放在一起以向用户输出一些消息:您所需要的只是一个好的格式化例程。(比如Python的unicode。格式,或。net的字符串。格式:任何允许位置符号(如"The {0} was in the {1}")的格式。很少情况下,您需要对用户的信息进行排序:这很简单:"为该用户找出合适的语言环境,使用该语言环境对数组进行排序,输出。"

如果你以前从未使用过Unicode,那么第一步就是使用它。根据你的语言,你可能已经有了,只是没有意识到而已。谷歌教程,阅读维基百科的文章。恕我直言,更重要的是,如果您正在处理文本数据,那么必须知道它使用的是什么编码。今天,这个答案,如果知道的话,几乎总是"utf -8"。对于序列化字节,或者对于内存中的东西,使用"utf -16";或"UTF-8" .

Unicode是未来的发展方向,例如,看看http://msdn.microsoft.com/en-us/library/windows/desktop/dd374089%28v=vs.85%29.aspx,他们已经说'一些新函数只支持Unicode版本'。标记单词'newer'. net字符串类是unicode,例如,Java字符串类也是unicode。

使用unicode是而不是一种黑暗艺术,实际上它使使用不同的语言变得非常容易。在我的一个业余项目中,我使用jsp接受用户对两种语言(由用户选择)的字典的输入,然后用Java处理它们(排序、提取子字符串、搜索、连接),最后使用JDBC将它们写入DB。之后,我可以搜索和检索他们从数据库,处理他们,并在http页面上显示他们。我必须将我的开发环境配置为支持UTF-8并始终使用UTF-8,但从我这样做的那一刻起,这对操作系统支持的每种语言/键盘布局都有效,而我甚至不再为此烦恼。包括日语,阿拉伯语,梵语,俄语。一个简单的鼠标点击改变键盘布局和程序工作都一样。这适用于linux, windows xp, windows 7,无论是32位还是64位。我使用的DB在所有这些环境中都支持这个功能,开发环境(eclipse/Java)也是如此。我再也不需要关心这些了。当然,如果你对阿拉伯字符串排序你应该知道一些关于阿拉伯语的知识,关于你的排序算法,关于你正在使用的字符串类的字符串比较。但这通常是有文档记录的。

配置开发环境当然意味着您知道与之相关的地方。这些包括但不限于将使用的字符串类、编辑器使用的编码、正在使用的模板(用于XML、HTML、资源文件等)的编码、数据库表、....但是,一旦您设置它始终使用一个且只有一个字符编码,这是一个非常强大且非常易于使用的设置。

你甚至不需要为unicode的细节而烦恼。如果这样做,您将发现,例如,可以找出某个区域设置中的所有字符位于哪个范围内,并且您可以通过提取该字符范围从unicode字符串中提取所有阿拉伯文本。真的可爱。

关键是在整个解决方案中始终使用一种编码。如果有不同的编码在使用,而你没有意识到这一点,这很可能成为严重头痛的根本原因。如果你有意识地同时使用不同的字符编码,并且它正确地工作,那么这可能是,事实上,接近一些黑暗艺术:-)如果你必须链接到不支持它的库,你将需要使用它。当然,这同样适用于不一致使用它的库。

(当然,即使您使用一种特定的编码,您也必须使自己熟悉您正在使用的字符串类。因此,如果您不需要支持一种以上的语言,最简单的方法就是使用您的开发环境的默认设置)。

Thanatos: Equality Comparision:...我只部分同意这一点。我不同意这不是unicode所特有的。这种复杂性的根源在于您所使用的区域设置。任何字符编码都需要支持这种特定于语言的特性,如果它声称支持相应的语言环境。当然,在字符串类库(或字体集)中提供这样的支持是很繁琐的。

而且这种支持只是在一定程度上是可能的。想想德语的变音符'ü'。在德语地区,这个字母的一个可能的替代是字母组合"我们"。"b geln"(德语中熨烫的意思)和"buegeln"在字典中会出现在同一个地方。去吧,在www.leo.org的德语-英语词典中试试。每个懂德语的人都知道"b geln"的意思,也知道"buegeln"的意思是一样的。

不是在德语中表示ü = ue。例如,"Ruegger"这个名字的发音是Ru-egger(不ü, e前面有一个声门停顿),如果有一个像"r gger"这样的单词存在,那么在字典中,"Ruegger"就会出现在"r gger"之前(因为就字典排序而言,u和ü通常被认为是相等的,e在g之前)。你需要知道这些单词才能分辨出这种区别。这种特定于语言的复杂性是而不是,因为任何人都可能使用unicode对用于书写该语言的字符进行编码。无论您使用何种编码,无论您使用何种字符串类,应用程序开发人员都需要知道语言的细节,以及字符串类如何以及在多大程度上支持它们。

英语世界的大多数人从来没有意识到这种复杂性,因为他们的语言在这方面不是很复杂,他们已经习惯了他们在日常工作中遇到的复杂性。(请告诉我为什么在ASCII中,所有大写字母都出现在小写字母之前。为什么不是A A B B C C ?这只是大家都习惯的惯例。如果您需要编写一个字典,其中a和a应该出现在同一位置,这是一件痛苦的事情)。当涉及到unicode时,这种复杂性似乎突然变得相关,因为您面对的是一个声称支持世界上几乎任何语言环境的概念。

然而,

相关的事实是,如果您从其他编码切换到unicode,那么您需要考虑排序和相等性检查等事情在启用unicode的字符串库中可能会被不同地对待。特别是,如果有人开始谈论一个包含大量字符串操作的软件项目的unicode迁移,您完全有理由感到紧张。这样的迁移意味着大量的作业,其中一个原因就是在排序和字符串的相等性检查方面的不同。另一个原因是unicode字符编码比经典的ANSI字符编码需要更多的空间,这使得字符迁移成为一个真正令人头痛的问题。

正如其他人指出的那样,这并不是很难,而且绝对不是一种黑暗艺术。但是有一点需要说明:排序和相等比较与Unicode没有太大关系,因为它们与本地约定有很大关系。因为这些都是语言环境敏感的操作。例如,德语对事物的排序不同于瑞典语,也不同于法语。

在Windows中,你可以使用CompareString(或CompareStringEx,如果你想用字符串语言环境标识符)。与ICU Collator (c++)或ucol_strcoll (C)做同样的事情。有时你会在Windows和ICU之间得到稍微不同的结果,因为Windows独立完成所有事情(有时比ICU更差,但有时更好)。

但总的来说,它是可以的(比非语言环境感知的比较要好得多)