【问题标题】:Unsigned integer as UTF-8 value无符号整数作为 UTF-8 值
【发布时间】:2013-11-26 22:26:43
【问题描述】:

假设我有

uint32_t a(3084);

我想创建一个存储 unicode 字符 U+3084 的字符串,这意味着我应该取 a 的值并将其用作 UTF8 表/字符集中正确字符的坐标。

现在,显然std::to_string() 对我不起作用,标准中有很多函数可以在数值和字符之间进行转换,我找不到任何支持我的 UTF8 并输出std::string .

我想问一下我是否必须从头开始创建这个函数,或者 C++11 标准中有什么可以帮助我的;请注意,我的编译器 ( gcc/g++ 4.8.1 ) 不完全支持codecvt。

【问题讨论】:

  • 请注意,整数 3084 实际上对应于字符 U+0C0C,因为 Unicode 代码点编号以十六进制表示。
  • @Wyzard 这只是问题的一部分,无论如何我也会对char而不是std::string作为输出感到满意。

标签: c++ c++11 unicode utf-8


【解决方案1】:

这里有一些不难转换为 C 的 C++ 代码。改编自 older answer。

std::string UnicodeToUTF8(unsigned int codepoint)
{
    std::string out;

    if (codepoint <= 0x7f)
        out.append(1, static_cast<char>(codepoint));
    else if (codepoint <= 0x7ff)
    {
        out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
        out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
    }
    else if (codepoint <= 0xffff)
    {
        out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
        out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
        out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
    }
    else
    {
        out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
        out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
        out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
        out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
    }
    return out;
}

【讨论】:

  • 它就是这样完美,我需要这个用于 C++ 11 非 C,谢谢。
  • @user2485710 这个问题最初被标记为 C 和 C++,这就是我提到它的原因。我看到你删除了那个标签。
  • 请注意,UTF-8 的 4 字节编码最多只能处理 U+1FFFFF 的代码点,但 unsigned int 最多可以达到 0xffffffff,因此您可能需要为此添加检查。
  • @RemyLebeau,如果您要担心无效的 Unicode,那么除了代码点越界之外,还有很多事情需要担心。我坚信垃圾进,垃圾出。也就是说,如果存在,这段代码已经去掉了高位。
【解决方案2】:

std::string_convert::to_bytes 有一个适合你的单字符重载。

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
#include <iomanip>

// utility function for output
void hex_print(const std::string& s)
{
    std::cout << std::hex << std::setfill('0');
    for(unsigned char c : s)
        std::cout << std::setw(2) << static_cast<int>(c) << ' ';
    std::cout << std::dec << '\n';
}

int main()
{
    uint32_t a(3084);

    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv1;
    std::string u8str = conv1.to_bytes(a);
    std::cout << "UTF-8 conversion produced " << u8str.size() << " bytes:\n";
    hex_print(u8str);
}

我得到(使用 libc++)

$ ./test
UTF-8 conversion produced 3 bytes:
e0 b0 8c 

【讨论】:

  • 这是codecvt 的第一个例子,我见过完美的工作。谢谢!
【解决方案3】:

C++ 标准包含 std::codecvt&lt;char32_t, char, mbstate_t&gt; 方面,它根据 22.4.1.4 [locale.codecvt] 第 3 段在 UTF-32 和 UTF-8 之间进行转换。遗憾的是,std::codecvt&lt;...&gt; 方面并不易于使用。在某些时候,有人讨论过过滤流缓冲区,这将处理代码转换(标准 C++ 库无论如何都需要为std::basic_filebuf&lt;...&gt; 实现它们),但我看不到这些的任何痕迹。

【讨论】:

  • 只有unsigned 到char 的转换没有什么?我注意到 UTF 支持是 C++ 标准的一部分,它只是在不同的实现中随机浮动,它可能是唯一处理“复杂”的部分,因为实现和执行都很差。
  • std::wstring_convert 并不是那么难用...
  • @Cubbi 在理论上是的,在实践中,它还没有为我的编译器/标准库实现。
【解决方案4】:
auto s = u8"\343\202\204"; // Octal escaped representation of HIRAGANA LETTER YA
std::cout << s << std::endl;

打印

や

对我来说(使用 g++ 4.8.1)。 s 具有 const char* 类型,正如您所料,但我不知道这是否是实现定义的。不幸的是,据我所知,C++ 不支持对 UTF8 字符串的操作。为此,您需要使用像 Glib::ustring 这样的库。

【讨论】:

  • 谢谢,但这是更简单的方法,在编译时,我在运行时需要它。
猜你喜欢
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多