将UTF-8字符转换为大/小写C++

6
我有一个包含UTF-8字符的字符串,并且我有一个方法,可以将每个字符转换为大写或小写。对于与ASCII重叠的字符,这很容易实现,显然有些字符无法转换,例如任何中文字符。但是,是否有一种好的方法来检测和转换其他可大写/小写的字符,例如所有希腊字符?还请注意,我需要在Windows和Linux上都能够执行此操作。
谢谢!

1
在这里,准确使用术语是非常重要的,以便获得有用的答案。UTF-8是RFC 3629(以及其他地方)中指定的字符编码;它包含了用于映射Unicode字符和表示这些字符的八位字节序列之间的算法,以便在不同系统之间进行移植。请精确使用类型;更好的做法是展示包括声明和类型的代码。 - President James K. Polk
1
Greg,很抱歉你的评论对我来说毫无意义,因为我还没有任何代码,我正在尝试弄清楚如何做某事,而不是尝试调试不正确的东西,所以这对我来说毫无意义,此外我知道UTF-8是一种编码,但这并不会改变我想要实现的目标,也就是开发一种方法,使得可以从“a”->“A”或者从“Ω”->“ω”。 - NSA
1
目的是什么?您打算用它来比较这些处理过的字符串吗?我假设您确实想要将其用于此类比较。您是否意识到,这将无法处理在德语中“ß”和“ss”等价的情况? - wilx
3个回答

16

请查看ICU

请注意,大小写转换函数是与语言环境有关的。以土耳其(ASCII)字母I为例,它被转换成“没有点的小写i”,而(ASCII)字母i则被转换成“带点的大写I”。


谢谢你的提示Alexandre,但是我的应用程序无法链接任何第三方库。因此,我需要想办法在不使用该库的情况下完成这个任务。 - NSA
1
我建议您编写自己的大小写映射实用程序,可以查看http://www.unicode.org/faq/casemap_charprop.html。从那里,您可以下载所有特殊案例映射。 - tidwall
3
C++并没有任何Unicode支持,ICU是最佳选择。 - Alexandre C.
@NSA:为什么你不能链接到另一个库? - wilx
1
@NSA 你可以在静态情况下链接 ICU。你可以重新实现它,但为什么呢?也许你可以更详细地解释一下你的排除。 - Steven R. Loomis

2
假设你可以访问wctype.h,那么将文本转换为2字节unicode字符串并使用towupper()函数进行转换,然后再将其转换回UTF-8编码。

1
请使用ICU,如Alexandre所提到的。 - tidwall
@Alexandre C.:无论这样的字符是否能正确转换取决于当前的语言环境。 - caf
2
@Alexandre C:甚至更强烈的是,正确性取决于语言环境。你对正确的看法并不被全世界所共享;最著名的例子就是土耳其字母i。 - MSalters
2
@caf,@MSalters:在德语eszett的情况下,大写字母B是SS(即两个字符,显然不被towupper处理),而对于希腊大写sigma,则有两种不同的选择,取决于它是否在单词的末尾(因此不被towlower处理)。再次,ICU解决了这些问题。 - Alexandre C.
@DevSolar 在这些评论中不发表冗长的抱怨,基本上归结为UTF-16不是固定宽度编码。(因为UCS-2最初是这样的,后来必须在不破坏兼容性的情况下进行扩展。)因此,在某些支持的语言环境中有多字节字符和字符无法适应Windows上的单个宽字符,这是标准理论上要求的。towupeer()函数及其类似的功能就是其中之一。 - Davislor
显示剩余4条评论

0
在Linux上,或者使用支持它的标准库,您可以获取适当区域设置的std::locale对象,因为大写转换是与区域设置相关的。将每个UTF-8字符转换为wchar_t,然后调用std::toupper(),然后再转换回UTF-8。请注意,结果字符串可能会更长或更短,并且某些连字可能无法正常工作:ß到德语中的Ss就是每个人都提到的例子。
在Windows上,这种方法的效果甚至更差,因为宽字符是UTF-16而不是固定宽度编码(这违反了C++语言标准,但也许标准委员会不应该试图欺骗微软打破Windows API)。CLR中有一个ToUpper方法。
使用可移植库(如ICU)可能更容易。
还要确保您想要的是大写(将每个字母都大写)还是标题大小写(将字符串的第一个字母或连字的第一部分大写)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接