我已经在文件系统中搜索了不可移植的名称中的字符。为此,我使用mbtowc函数来检查每个字符。
在OSX上,我尝试过:
//在OSX上
#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{
string s1 = "Ä";
size_t len = s1.length(); // will be 2, ok
const char* s1c = s1.c_str(); // 0xC3 0x84 0x00, ok
char a = s1[0]; // 0xc3, ok
char b = s1[1]; // 0x84, ok
mbtowc(NULL,NULL,0); // reset
wchar_t wc;
int mb_len = mbtowc(&wc,s1c,len); // mb_len = 1, wc=0xc3 00 00 00
// why only one byte?
// how can i get the right Wchar???
char mb2[10];
int mblen2 = wctomb(mb2,wc); // mblen2 = 1; mb2 = 0xC3
string s2 = string(mb2); // len = 1 only 0xC3
return 0;
}为什么mbtows对所有的char只返回1?
赫伯特
发布于 2012-11-27 03:23:38
您的程序在C语言环境中启动,它将字符串视为ASCII (或未指定的ASCII兼容的8位编码)。因此,mbtowc()只是将字符串中的第一个字节复制到wchar_t中。您需要在使用UTF-8的语言环境中调用setlocale(LC_CTYPE, locale),因为您的源代码是以UTF-8编码的,因此字符串常量也是如此。
setlocale(LC_CTYPE, "")使用用户的当前语言环境设置,因此如果您要读取用户提供的文件,它是合适的;但是,如果有人试图在不使用UTF-8语言环境的机器上运行您的程序,您的示例可能会失败。您可以改用setlocale(LC_CTYPE, "UTF-8"),这是一种始终使用UTF-8的语言环境(我不相信它是标准化的,但至少在我的Mac和Linux机器上是存在的)。
下面是一个例子(为了简单起见,这次使用纯C语言,而不是C++ )。我添加了一些printfs来显示正在发生的事情。它在调用setlocale()之前和之后运行相同的mbtowc()。
#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <stdlib.h>
void test_mbtowc(char *s) {
size_t len = strlen(s);
wchar_t wc;
mbtowc(NULL,NULL,0);
int mb_len = mbtowc(&wc,s,len);
printf("%d, %08x\n", mb_len, wc);
}
int main()
{
char *s = "Ä";
printf("%02hhx %02hhx %02hhx\n", s[0], s[1], s[2]);
test_mbtowc(s);
setlocale(LC_CTYPE, "UTF-8");
test_mbtowc(s);
return 0;
}这是输出。如您所见,我们将字符串编码为UTF-8。对mbtowc的第一个调用只是简单地复制第一个字节;mb_len是1,我们得到的结果是c3。第二个代码给出了2的mb_len和c4,这是Ä在wc中的Unicode码点。
c3 84 00
1, 000000c3
2, 000000c4发布于 2012-11-27 03:55:56
mbtowc()使用C语言环境来确定要在其间进行转换的编码。C语言环境总是以"C"开头,这不能保证支持基本字符集(ASCII码支持的抽象字符集的一个子集)之外的任何字符。
默认情况下,OS在其他任何地方都使用UTF8,因此mbtowc()不会在您期望的编码之间进行转换。
您可以将C语言环境设置为使用适当编码的语言环境。如果您在C++程序中执行此操作,则可能应该通过设置C++全局区域设置(这将反过来设置C区域设置)来完成此操作:
std::locale::global(std::locale("en_US.UTF-8")); // locale names are not portable但是,扰乱区域设置通常不是一件好事。全局语言环境本质上是一个全局变量,并且有所有反对使用它的正常原因。它有广泛的影响,例如,它可以影响sprintf()在某些库中的一些使用,这些库可能依赖于没有被设置为某些地区。此外,对区域设置敏感的函数可能不是线程安全的和/或可重入的。
OS X有一个“扩展区域设置支持”库(标题<xlocale.h>),其中包含*_l版本的区域设置敏感函数,这些函数采用额外的区域设置参数,而不是使用全局区域设置。这解决了全球语言环境的许多问题。我相信它甚至被用来在OS上实现许多标准的C++语言环境功能。
locale_t loc = newlocale(LC_ALL_MASK, "en_US.UTF-8", NULL);
char buf[MB_CUR_MAX_L(loc)];
mbstate_t state = {};
wcrtomb_l(buf, L'A', &state, loc);
freelocale(loc);iconv是一个允许在大量编码之间直接转换的API。C++还支持在某些编码之间进行转换,特别是使用wstring_convert模板和一些标准编解码器方面(codecvt_utf8、codecvt_utf8_utf16)在各种Unicode编码(UTF-8、UTF-16和UTF-32)之间进行转换。
当然,只有当您确实需要在编码之间进行转换时,所有这些才重要。目前还不清楚这是否仅仅是为了“在文件系统中搜索不可移植的名称中的字符”。如果您有一个您认为合法的代码点列表(或一个非法的代码点列表),那么在UTF-8字符串中直接搜索这些代码点的UTF-8编码应该不是那么困难,不需要进行转换。
https://stackoverflow.com/questions/13570891
复制相似问题