如何将代码点转换为 utf-8?
How to convert a codepoint to utf-8?
我有一些代码读取 unicode 代码点(在字符串 0xF00 中转义)。
由于我使用 boost,我推测以下是否是最佳(和正确)方法:
unsigned int codepoint{0xF00};
boost::locale::conv::utf_to_utf<char>(&codepoint, &codepoint+1);
?
您可以使用标准库使用 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);
}
这个 returns 一个 std::string
大小为 1、2、3 或 4,具体取决于 codepoint
的大小。如果代码点太大(> 0x10FFFF,最大 unicode 代码点),它将抛出 std::range_error
。
你的 boost 版本似乎在做同样的事情。 The documentation 表示 utf_to_utf
函数将 UTF 编码转换为另一种编码,在本例中为 32 到 8。如果您使用 char32_t
,这将是一种 "correct" 方法,即将在 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);
}
如前所述,此形式的代码点是(方便地)UTF-32,因此您正在寻找的是转码。
对于不依赖自 C++17 以来不推荐使用的函数的解决方案,并且不是很丑陋,也不需要大量 third-party 库,您可以使用非常轻量级的 UTF8-CPP(四小headers!)及其函数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
,如果你对异常过敏的话。)
(并考虑阅读 vector<char8_t>
或 std::u8string
,自 C++20 起)。
(最后,请注意,我专门使用 uint32_t
来确保输入具有正确的宽度。)
我倾向于在项目中使用这个库,直到我需要一些更重的东西用于其他目的(此时我通常会切换到 ICU)。
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,
buf, buf+sz, last_out);
sz = last_out - buf;
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
)
在阅读了 C++ 中 UTF-8 支持的不稳定状态后,我偶然发现了相应的 C 支持 c32rtomb
,这看起来很有前途,而且可能不会很快被弃用
#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;
}
用法将是
char32_t codepoint{0xfff};
char buf[MB_LEN_MAX]{};
size_t len = to_utf8(codepoint, buf);
如果您的应用程序的当前语言环境已经是 UTF-8,您当然可以省略对 setlocale
的来回调用。
我有一些代码读取 unicode 代码点(在字符串 0xF00 中转义)。
由于我使用 boost,我推测以下是否是最佳(和正确)方法:
unsigned int codepoint{0xF00};
boost::locale::conv::utf_to_utf<char>(&codepoint, &codepoint+1);
?
您可以使用标准库使用 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);
}
这个 returns 一个 std::string
大小为 1、2、3 或 4,具体取决于 codepoint
的大小。如果代码点太大(> 0x10FFFF,最大 unicode 代码点),它将抛出 std::range_error
。
你的 boost 版本似乎在做同样的事情。 The documentation 表示 utf_to_utf
函数将 UTF 编码转换为另一种编码,在本例中为 32 到 8。如果您使用 char32_t
,这将是一种 "correct" 方法,即将在 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);
}
如前所述,此形式的代码点是(方便地)UTF-32,因此您正在寻找的是转码。
对于不依赖自 C++17 以来不推荐使用的函数的解决方案,并且不是很丑陋,也不需要大量 third-party 库,您可以使用非常轻量级的 UTF8-CPP(四小headers!)及其函数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
,如果你对异常过敏的话。)
(并考虑阅读 vector<char8_t>
或 std::u8string
,自 C++20 起)。
(最后,请注意,我专门使用 uint32_t
来确保输入具有正确的宽度。)
我倾向于在项目中使用这个库,直到我需要一些更重的东西用于其他目的(此时我通常会切换到 ICU)。
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,
buf, buf+sz, last_out);
sz = last_out - buf;
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
)
在阅读了 C++ 中 UTF-8 支持的不稳定状态后,我偶然发现了相应的 C 支持 c32rtomb
,这看起来很有前途,而且可能不会很快被弃用
#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;
}
用法将是
char32_t codepoint{0xfff};
char buf[MB_LEN_MAX]{};
size_t len = to_utf8(codepoint, buf);
如果您的应用程序的当前语言环境已经是 UTF-8,您当然可以省略对 setlocale
的来回调用。