字符编码

一、编码介绍:

ASCII 编码 【SBCS(单字节字符集)】:

ASCII编码,就是英文显示文字所需要的256个字符(比如,英文字母、数字、标点符号等等)

ANSI 编码 【MBCS(多字节字符集)】

ANSI编码,像中文,肯定不能只用256个字符就代表所有汉字。因此对ASCII码表进行了扩展,使用两个(或多个)字节,代表一个汉字。类似的,不同的国家和地区制定了不同的标准,这些使用 2 个字节来代表一个字符的各种延伸编码方式,称为 ANSI 编码。也就是说,ANSI是一种对ASCII码表进行扩展的泛称,不同语言操作系统,其代表的编码方式不一样。比如中文操作系统,ANSI编码就代指GB2312;日文操作系统ANSI编码就代指JIS。

UNICODE 编码 【DBCS(宽字节字符集)】

Unicode是一个超大的集合,也是一个统一的标准,可以容纳世界上的所有语言符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,“汉”这个字的Unicode编码是U+6C49。

代码页(codepage)

Unicode是一个世界统一的标准,也就是说,如果一个文本是用Unicode方式编码的,那么它可以同时显示中文、日文、阿拉伯文等等,并且是在任何系统上都可以正常显示的。但是由于ANSI编码之间互不兼容,因此就需要有一个标识来表明不同的ANSI编码到Unicode之间的映射关系(也就是不同编码之间的映射关系),这个就是代码页。比如简体中文的代码页是CP_936(中文系统默认的代码页),这个也就是windows API中MultiByteToWideChar第一个参数所代表的含义。如果不标明代码页,系统是不知道如何进行编码转换的。

中文常见编码

GB2312(CP_20936)->GBK(CP_936)->GB18030(CP_54936),三种编码方式向下兼容,也就是说GB18030包含GB2312的所有字符。GB18030在2000年取代GBK成为正式国家标准。

UTF

UCS(Unicode Character Set):UCS-2规定了2个字节代表一个文字,还有UCS-4规定了4个字节代表一个文字。我们工作中几乎总是在和UCS-2打交道。

UTF(UCS Transformation Format):UCS只是规定的如何编码,但是没有规定如何传输、保存这个编码。UTF则规定了由几个字节保存这个编码。UTF-7,UTF-8,UTF-16都是比较常见的编码方式。UTF-8编码与Unicode编码并不相同,但是它们之间可以通过计算进行转换,而不像ANSI和Unicode之间必须通过一个映射表来人为规定其对应关系。UTF-16完全对应于UCS-2,并可通过计算代表一部分UCS-4文字。还有UTF-32则是完全对应于UCS-4,不过很不常见就是了。

UTF-8是与ASCII码兼容的,英文字母1个字节,汉字通常是3个字节;UTF-16的所有字符都是用2个字节进行保存,其编码与Unicode是等价的。UTF-16又分为UTF-16LE(little endian)和UTF-16BE(big endian),比如一个字母'a',如果按utf-8来存,就是0x61;如果按utf-16le来存就是0x61 0x00(低有效位在前);如果按utf-16be来存就是0x00 0x61(高有效位在前)。这个也就是我们用记事本另存文件的时候可以选择的几个编码方式的含义。

编码转换:

windows 系统:

windows 中文系统采用 GBK 编码,Unicode 字符集是 UTF-16 编码。因此 char 类型的字符串为 GBK 编码,wchar_t 大小为 UTF-16 编码,大小为 2字节。

windows 系统编码转换可以使用 windows API : 

WideCharToMultiByte \\ 宽字节转多字节 wstring->string 
MultiByteToWideChar \\ 多字节转宽字节 string-> wstring

注意:由于 GBK 和 UTF-8 都属于多字节字符集,因此GBK 和UTF-8 互转时,都是先转成 宽字节 然后再转多字节(如有其它大神有其他方法,可以留言)

// ascii 转为 unicode
	inline std::wstring AsciiToUnicode(const std::string& str)
	{
		int unicodeLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);   
		wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);    
		MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, pUnicode, unicodeLen);  
		std::wstring ret_str = pUnicode;  
		free(pUnicode);  
		return ret_str; 
	}

	// unicode 转为 utf8
	inline std::string UnicodeToUtf8(const std::wstring& wstr)
	{
		int ansiiLen = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);     
		char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);
		WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);  
		std::string ret_str = pAssii;  
		free(pAssii);  
		return ret_str;  
	}

	// utf8 转为 unicode
	inline std::wstring Utf8ToUnicode(const std::string& str)
	{
		int unicodeLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);   
		wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);     
		MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, pUnicode, unicodeLen);  
		std::wstring ret_str = pUnicode;  
		free(pUnicode);  
		return ret_str;  
	}

	// unicode 转为 ascii
	inline std::string UnicodeToAscii(const std::wstring& wstr)
	{
		int ansiiLen = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);   
		char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);    
		WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);  
		std::string ret_str = pAssii;  
		free(pAssii);  
		return ret_str;  
	}


	// ascii 转为 utf8
	inline std::string AsciiToUtf8(const std::string& str)
	{
		return UnicodeToUtf8(AsciiToUnicode(str)); 
	}


	// utf8 转为 ascii
	inline std::string  Utf8ToAscii(const std::string& str)
	{
		return UnicodeToAscii(Utf8ToUnicode(str)); 
	}

Linux 系统:

由于最近刚研究 linux 系统,存在不足请多多指教。

linux 系统中中文字符集 一般采用 zh_CN_UTF-8 编码。因此 char 类型字符串默认编码形式为 UTF-8 编码。linux 系统中 wchar_t 是 UTF-32 编码,大小为 4 字节。因此文件读写跨平台时需要注意哦!!

 linux 系统中编码转换可以使用自带库 iconv,具体用法可以百度。

注意:string 转 wstring 时 iconv_open 一定要设置对 编码哦,这里由于对 linux 系统不是很熟悉,我一开始一直以为 是 GBK 转 UTF-32 一直不成功,后来发现应该是 UTF-8 转 UTF-32

std::string Unicode2Acsii(const wchar_t *wcsInputBuffer)
{
    iconv_t cd = iconv_open("utf-8", "utf-32le");
    if (cd == nullptr)
    {
        return "";
    }
    size_t inSize = (wcslen(wcsInputBuffer) + 1) * sizeof(wchar_t);
    char *inBuffer = new char[inSize];
    memset(inBuffer, 0, inSize);
    memcpy(inBuffer, wcsInputBuffer, inSize);

    size_t outLen = (wcslen(wcsInputBuffer) + 1) * sizeof(wchar_t);

    char *pTemp = new char[outLen];
    char *pOut = pTemp;

    memset(pTemp, 0, outLen);

    size_t ret = iconv(cd, &inBuffer, &inSize, &pTemp, &outLen);

    *pTemp = '\0';

    if (ret == -1)
    {
        return "";
    }

    std::string strOut = pOut;

    iconv_close(cd);

    delete[] inBuffer;
    inBuffer = nullptr;

    delete[] pOut;
    pOut = nullptr;
    pTemp = nullptr;

    return strOut;
}

当然为了跨平台,我们可以使用 C++ 标准库中函数进行 多字节和宽字节字符串的转换。

两个库函数分别 为 wcstombs 和 mbstowcs

使用这两个函数之前要调用 setlocale 函数设置系统字符集哦 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值