如何在C++中将Unicode字符转换为大写

3

我正在学习C++中的Unicode,但是我很难让它正常工作。我尝试将单个字符视为uint64_t。如果我只需要打印字符,那么它可以正常工作,但问题在于我需要将它们转换为大写字母。我可以将大写字母存储在数组中,并且只需使用与小写字母相同的索引,但我正在寻找更优雅的解决方案。我发现了这个类似的问题,但大多数答案都使用了宽字符,这不是我能使用的东西。这是我的尝试:

#include <iostream>
#include <locale>
#include <string>
#include <cstdint>
#include <algorithm>

// hacky solution to store a multibyte character in a uint64_t
#define E(c) ((((uint64_t) 0 | (uint32_t) c[0]) << 32) | (uint32_t) c[1])

typedef std::string::value_type char_t;
char_t upcase(char_t ch) {
    return std::use_facet<std::ctype<char_t>>(std::locale()).toupper(ch);
}

std::string toupper(const std::string &src) {
    std::string result;
    std::transform(src.begin(), src.end(), std::back_inserter(result), upcase);
    return result;
}

const uint64_t VOWS_EXTRA[]
{
E("å")  , E("ä"), E("ö"), E("ij"), E("ø"), E("æ")
};

int main(void) {
    char name[5];
    std::locale::global(std::locale("sv_SE.UTF8"));
    name[0] = (VOWS_EXTRA[3] >> 32) & ~((uint32_t)0);
    name[1] = VOWS_EXTRA[3] & ~((uint32_t)0);
    name[2] = '\0';
    std::cout << toupper(name) << std::endl;
}

我希望这段代码能够打印出字符IJ,但实际上它打印出了与一开始相同的字符(ij)。

(编辑:好的,我在这里阅读了更多关于标准C++对Unicode的支持。看起来最好的选择是使用ICU或Boost.locale来完成此任务。由于C++将std::string视为二进制数据块,因此似乎不容易正确地将Unicode字母大写。我认为,我的uint64_t hacky解决方案并没有比C++标准库更有用,甚至可能更糟。我会很感激一个使用ICU实现上述行为的示例。)


请不要试图假装Unicode是固定宽度编码。 - Nicol Bolas
@NicolBolas 抱歉,我对Unicode非常不熟悉,我尝试使用普通字符串,但无法使用单个字符。 - Linus
std::locale::global(std::locale("sv_SE.UTF8"))在Windows上是不兼容的,除非你使用非常特殊的编译器。微软的运行时不支持UTF-8语言环境。请参阅setlocale的文档。 - Cheers and hth. - Alf
要包含UTF-8文字,只需使用例如u"Oh, it's that easy?"。主要问题是基本字符类型仍然是“char”。 - Cheers and hth. - Alf
对于完整的Unicode,大写和小写不能通常基于单个字符进行转换。有时一个字符映射到相反情况下的两个字符。我认为对于希腊语来说,它取决于单词中字符的位置,或者是在结尾(还是开始?)。对于真正的学究来说,甚至不能以与区域设置无关的方式完成此操作(这是土耳其语的特殊问题),但我认为几乎所有软件都忽略了这个细节。 - Cheers and hth. - Alf
2个回答

4
请查看ICU用户指南,如果需要简单(单个字符)大小写转换,可以使用u_toupper。如果需要完整的大小写转换,则使用u_strToUpper。示例代码:
#include <unicode/uchar.h>
#include <unicode/ustdio.h>
#include <unicode/ustring.h>

int main() {
    UChar32 upper = u_toupper(U'ij');
    u_printf("%lC\n", upper);

    UChar src = u'ß';
    UChar dest[3];
    UErrorCode err = U_ZERO_ERROR;
    u_strToUpper(dest, 3, &src, 1, NULL, &err);
    u_printf("%S\n", dest);

    return 0;
}

谢谢,对于回答晚了我很抱歉。我花了几个小时才让 ICU 起作用。在这个过程中,我遇到了很多"未定义函数引用"的问题。 - Linus

0

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