【问题标题】:How to convert unicode characters to uppercase in C++如何在 C++ 中将 unicode 字符转换为大写
【发布时间】:2017-01-26 10:02:47
【问题描述】:

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

#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 支持here。似乎我最好的选择是使用 ICU 或 Boost.locale 之类的东西来完成这项任务。 C ++本质上将std :: string视为二进制数据的blob,因此正确大写unicode字母似乎不是一件容易的事。我认为我使用uint64_t的hacky解决方案并不比C ++标准库更有用如果不是更糟。我将不胜感激有关如何使用 ICU 实现上述行为的示例。)

【问题讨论】:

  • 请不要假装 Unicode 是固定宽度的编码。
  • @NicolBolas 抱歉,我对 unicode 非常缺乏经验,我尝试使用常规字符串,但无法使用单个字符。
  • std::locale::global(std::locale("sv_SE.UTF8")) 与 Windows 不兼容,除非您使用非常特殊的编译器。 Microsoft 的运行时不支持 UTF-8 语言环境。请参阅setlocale 的文档。
  • 要包含 UTF-8 文字,只需使用例如u"Oh, it's that easy?"。主要问题是基本字符类型还是char。
  • 完整 Unicode 的大写和小写通常不能逐个字符地完成。有时,在相反的情况下,单个字符映射到两个字符。而且我认为对于希腊语,这取决于字符在单词中的位置,或者在结尾(或者是开头?)。对于真正迂腐的人来说,它甚至不能以独立于语言环境的方式完成(这是土耳其语的一个特殊问题),但我认为几乎所有软件都忽略了这一点。

标签: c++ c++11 unicode locale uppercase


【解决方案1】:

如果其他人正在寻找它,std::towupper 和 std::towlower 似乎工作正常 https://en.cppreference.com/w/cpp/string/wide/towupper

【讨论】:

    【解决方案2】:

    看看ICU User Guide。对于简单(单字符)大小写映射,您可以使用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 工作。我遇到了很多关于“未定义的函数引用”错误的问题。
    猜你喜欢
    • 2013-08-02
    • 2021-10-05
    • 2014-06-18
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-03
    相关资源
    最近更新 更多