UNICODE, UTF-8 and Windows mess
UNICODE, UTF-8 and Windows mess
我正在尝试在Windows中实现文本支持,目的是以后还搬到Linux平台。以统一的方式支持国际语言是理想的选择,但是考虑到这两个平台时,这似乎并不容易完成。我花了大量时间阅读Unicode,UTF-8(和其他编码),Widechars等,这是我到目前为止所了解的:
Unicode作为标准,描述了可映射的字符集和发生的顺序。我将其称为"什么":Unicode指定将有什么可用。
utf-8(和其他编码)指定:如何以二进制格式表示每个字符。
现在,在Windows上,他们最初选择了UCS-2编码,但未能满足要求,因此UTF-16是他们拥有的,在必要时也是多ch的。
所以这是三人:
- Windows仅在内部使用UTF-16,因此,如果您想支持国际角色,则被迫将其转换为Widechar版本以相应地使用OS调用。似乎没有任何支持使用多字节UTF-8字符串来调用CreateFilea()之类的东西,并且看起来很合适。这是正确的吗?
- 在C中,有一些多字节支持函数(_mbscat,_mbscpy等),但是,在Windows上,字符类型定义为这些函数的无符号字符*。鉴于_MBS系列函数不是一个完整的集合(即没有_mbstol可以将多字节字符串转换为长的_mbstol,例如,您被迫使用运行时函数的某些char*版本,由于这些功能之间的签名/未签名类型差异,这导致了编译器问题。有人使用这些吗?您只是做一大堆铸造以解决错误吗?
- 在C 中,STD :: String具有迭代器,但它们基于Char_Type,而不是代码点。因此,如果我在std :: string :: iterator上做A ,我将获得下一个char_type,而不是下一个代码点。同样,如果您调用std :: string :: operator [],您将获得对char_type的引用,该char_type具有很大的潜力,即不成为完整的代码点。那么,如何按代码点迭代std ::字符串呢?(C具有_mbsinc()函数)。
只是做UTF-8
在每个细胞中,UTF-8都有很多支持库,有些也是多平流。正如您已经指出的那样,Win32中的UTF-16 API有限且不一致,因此最好将所有内容保留在UTF-8中,并终于转换为UTF-16。Windows API也有一些方便的UTF-8包装。
此外,在应用程序级文档中,UTF-8越来越被标准化。每个文本处理应用程序要么接受UTF-8,要么在最坏的情况下显示为" ASCII,具有一些dingbats",而只有很少的应用程序支持UTF-16文档,而那些不支持它的文档,将其显示为"很多whitespace!
正确。您将以Windows API调用将UTF-8转换为UTF-16。
大多数时候,您将使用常规字符串函数用于UTF-8-strlen
,strcpy
(ICK),snprintf
,strtol
。它们将使用UTF-8字符正常工作。要么将char *
用于UTF-8,要么您必须施放所有内容。
请注意,诸如_mbstowcs
之类的下划线版本不是标准的,通常没有下划线,例如mbstowcs
。
很难想到您实际上想在Unicode字符串上使用operator[]
的示例,我的建议是远离它。同样,在字符串上进行迭代的用途很少:
-
如果您要解析字符串(例如,字符串是C或JavaScript代码,也许您需要语法Hilighting),那么您可以完成大部分的工作字节字节,而忽略了多重型方面。
-
如果您正在进行搜索,则还将执行此字节字节(但请记住要首先归一化)。
-
如果您正在寻找单词断开或素数集群边界,则需要使用像ICU这样的库。该算法并不简单。
-
最后,您始终可以将一块文本转换为UTF-32并以这种方式使用。我认为,如果您要实现任何Unicode算法(例如Compration或Breaking)。
请参阅:C 迭代或将UTF-8字符串分为符号数组?
- Windows仅在内部使用UTF-16,因此,如果您想支持国际角色,则被迫将其转换为Widechar版本以相应地使用OS调用。似乎没有任何支持使用多字节UTF-8字符串来调用CreateFilea()之类的东西,并且看起来很合适。这是正确的吗?
是的,这是正确的。*A
函数变体根据当前活动的代码页面解释字符串参数(在美国和西欧的大多数计算机上是Windows-1252,但通常可以是其他代码页),并将其转换为UTF-16。有一个UTF-8代码页面,但是AFAIK没有办法可以编程设置活动代码页(有GetACP
获取活动代码页,但没有对应的SetACP
)。
- 在C中,有一些多字节支持函数(_mbscat,_mbscpy等),但是,在Windows上,字符类型定义为这些函数的无符号字符*。鉴于_MBS系列函数不是一个完整的集合(即没有_mbstol可以将多字节字符串转换为长的_mbstol,例如,您被迫使用运行时函数的某些char*版本,由于这些功能之间的签名/未签名类型差异,这导致了编译器问题。有人使用这些吗?您只是做一大堆铸造以解决错误吗?
根据我的经验,mbs*
功能系列几乎从未使用过。除mbstowcs
,mbsrtowcs
和mbsinit
外,这些功能不是标准c。
- 在C 中,STD :: String具有迭代器,但它们基于Char_Type,而不是代码点。因此,如果我在std :: string :: iterator上做A ,我将获得下一个char_type,而不是下一个代码点。同样,如果您调用std :: string :: operator [],您将获得对char_type的引用,该char_type具有很大的潜力,即不成为完整的代码点。那么,如何按代码点迭代std ::字符串呢?(C具有_mbsinc()函数)。
我认为mbrtowc(3)
将是解码多键字符串的单个代码点的最佳选择。
总的来说,我认为跨平台Unicode兼容性的最佳策略是使用单字节字符在内部完成UTF-8的所有操作。当您需要调用Windows API函数时,将其转换为UTF-16,并始终调用*W
变体。大多数非Windows平台已经使用UTF-8,因此可以将其捕捉。
在Windows中,您可以调用WideCharToMultiByte
和MultiByteToWideChar
之间转换UTF-8字符串和UTF-16字符串(Windows中的WSTRING)。由于Windows API不使用UTF-8,因此每当您调用任何支持Unicode的Windows API函数时,都必须将字符串转换为WSTRING(UTF-16中的Unicode的Windows版本)。当您从Windows获得输出时,必须将UTF-16转换回UTF-8。Linux在内部使用UTF-8,因此您不需要这种转换。要使您的代码移植到Linux,请坚持使用UTF-8,并提供以下转换的内容:
#if (UNDERLYING_OS==OS_WINDOWS)
using os_string = std::wstring;
std::string utf8_string_from_os_string(const os_string &os_str)
{
size_t length = os_str.size();
int size_needed = WideCharToMultiByte(CP_UTF8, 0, os_str, length, NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, os_str, length, &strTo[0], size_needed, NULL, NULL);
return strTo;
}
os_string utf8_string_to_os_string(const std::string &str)
{
size_t length = os_str.size();
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, length, NULL, 0);
os_string wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, str, length, &wstrTo[0], size_needed);
return wstrTo;
}
#else
// Other operating system uses UTF-8 directly and such conversion is
// not required
using os_string = std::string;
#define utf8_string_from_os_string(str) str
#define utf8_string_to_os_string(str) str
#endif
要迭代UTF8字符串,您需要的两个基本函数是:一个用于计算UTF8字符的字节数,而另一个可以确定字节是否是UTF8字符序列的领导字节。以下代码提供了一种非常有效的测试方法:
inline size_t utf8CharBytes(char leading_ch)
{
return (leading_ch & 0x80)==0 ? 1 : clz(~(uint32_t(uint8_t(leading_ch))<<24));
}
inline bool isUtf8LeadingByte(char ch)
{
return (ch & 0xC0) != 0x80;
}
使用这些功能,不难在UTF8字符串上实现自己的迭代器,一个是用于转发迭代器,另一个用于落后迭代器。
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 在Linux for Windows上编译C++代码时出错
- 在Windows上用C++裁剪HBITMAP
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 如何加载(或映射)文件部分的最大大小,但适合在Windows上的RAM
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 当我编译webrtc服务器时,Windows上只支持clang-cl
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- Windows/Cygwin - 不能使用 pybind11 - 犯错误
- Windows 10-使用gtkmm-3.0库和g++[包括再现]的分段故障
- 在Windows中以.exe的形式运行c++
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 无法在windows控制台中为C++程序提供必要的输入
- 在Windows中查找扬声器输出的当前音量级别
- Windows.h与GLFW.h的接口
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 在Linux和C++中的Windows上,散列字符串值会产生不同的输出
- Active Directory:从网络服务帐户下运行的Windows服务调用ADsOpenObject时失败
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- UNICODE, UTF-8 and Windows mess