我有一些代码可以读取unicode代码点(以0xF00字符串形式转义)。
自从我使用boost以来,我一直在猜测以下方法是否是最佳(也是正确的)方法:
unsigned int codepoint{0xF00};
boost::locale::conv::utf_to_utf<char>(&codepoint, &codepoint+1);
?
答案 0 :(得分:4)
如前所述,这种形式的代码点(通常是UTF-32),所以您要查找的是转码。
对于不依赖自C ++ 17以来不推荐使用的功能并且不十分丑陋且不需要大量第三方库的解决方案,可以使用非常轻量级的UTF8-CPP(四个小标题!)及其功能utf8::utf32to8
。
它将看起来像这样:
const uint32_t codepoint{0xF00};
std::vector<unsigned char> result;
try
{
utf8::utf32to8(&codepoint, &codepoint + 1, std::back_inserter(result));
}
catch (const utf8::invalid_code_point&)
{
// something
}
(如果您对例外情况过敏,也可以使用utf8::unchecked::utf32to8
。)
(并考虑从C ++ 20开始读入vector<char8_t>
或std::u8string
)。
(最后,请注意,我专门使用uint32_t
来确保输入的宽度正确。)
我倾向于在项目中使用该库,直到我需要一些其他用途的东西为止(此时,我通常会切换到ICU)。
答案 1 :(得分:3)
您可以使用std::wstring_convert
使用标准库来完成此操作,以将UTF-32(代码点)转换为UTF-8:
#include <locale>
#include <codecvt>
std::string codepoint_to_utf8(char32_t codepoint) {
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
return convert.to_bytes(&codepoint, &codepoint + 1);
}
这将返回一个std::string
,其大小为1、2、3或4,具体取决于codepoint
的大小。如果代码点太大(大于0x10FFFF,即最大unicode代码点),它将抛出std::range_error
。
您的带有Boost的版本似乎在做同样的事情。 The documentation表示utf_to_utf
函数将UTF编码转换为另一种,在这种情况下为32到8。如果您使用char32_t
,这将是一种“正确”的方法,它将起作用在unsigned int
与char32_t
大小不同的系统上。
// The function also converts the unsigned int to char32_t
std::string codepoint_to_utf8(char32_t codepoint) {
return boost::locale::conv::utf_to_utf<char>(&codepoint, &codepoint + 1);
}
答案 2 :(得分:2)
C ++ 17已弃用许多处理utf的便利功能。不幸的是,最后剩下的将在C ++ 20 (*)中弃用。所说的std::codecvt
仍然有效。从C ++ 11到C ++ 17,您可以使用std::codecvt<char32_t, char, mbstate_t>
,从C ++ 20开始,它将是std::codecvt<char32_t, char8_t, mbstate_t>
。
以下是一些代码,用于转换utf8中的代码点(最多0x10FFFF):
// codepoint is the codepoint to convert
// buff is a char array of size sz (should be at least 4 to convert any code point)
// on return sz is the used size of buf for the utf8 converted string
// the return value is the return value of std::codecvt::out (0 for ok)
std::codecvt_base::result to_utf8(char32_t codepoint, char *buf, size_t& sz) {
std::locale loc("");
const std::codecvt<char32_t, char, std::mbstate_t> &cvt =
std::use_facet<std::codecvt<char32_t, char, std::mbstate_t>>(loc);
std::mbstate_t state{{0}};
const char32_t * last_in;
char *last_out;
std::codecvt_base::result res = cvt.out(state, &codepoint, 1+&codepoint, last_in,
c, c+sz, last_out);
sz = last_out - c;
return res;
}
(*) std::codecvt
在C ++ 20中仍然存在。只是默认实例化将不再是std::codecvt<char16_t, char, std::mbstate_t>
和std::codecvt<char32_t, char, std::mbstate_t>
,而是std::codecvt<char16_t, char8_t, std::mbstate_t>
和std::codecvt<char32_t, char8_t, std::mbstate_t>
(请注意,char8_t
而不是char
)
答案 3 :(得分:1)
在阅读了有关C ++中UTF-8支持的不稳定状态后,我偶然发现了相应的C支持c32rtomb
,它看起来很有希望,而且很可能很快就会被弃用
*if(rs.next())
{
rs.last();
totalNumberOfRecords=rs.getRow();
rs.beforeFirst();
}*
用法将是
#include <clocale>
#include <cuchar>
#include <climits>
size_t to_utf8(char32_t codepoint, char *buf)
{
const char *loc = std::setlocale(LC_ALL, "en_US.utf8");
std::mbstate_t state{};
std::size_t len = std::c32rtomb(buf, codepoint, &state);
std::setlocale(LC_ALL, loc);
return len;
}
如果应用程序的当前语言环境已经是UTF-8,则可以省略对char32_t codepoint{0xfff};
char buf[MB_LEN_MAX]{};
size_t len = to_utf8(codepoint, buf);
的来回调用。