他小的有

Windows字符串编码转换,char/wchar_t/utf-8之间相互转换

字符串乱码往往是由于编码不一致或编码没有对应的字符所致,为了能够正常显示字符串,经常会有需要编码转换的需要,为了方便使用这里整理成一个head-only文件,这里提供了char、wchar_t、utf-8之间的转换,在实际的项目中建议使用wchar_t/utf-8,强烈建议使用utf-8。

//ZEncode.hpp

#pragma once
#include <Windows.h>
#include <string>
#include <vector>
#include <assert.h>

/*!
 * 编码转换命名空间
 * 
 */
namespace ZEncode
{
	/*!
	 * 窄字节转宽字节
	 * 
	 * \param str 窄字节
	 * \param uCodePage 窄字节编码
	 * \return 宽字节
	 */
	static std::wstring A2W(const std::string &str, UINT uCodePage)
	{
		int nLength = ::MultiByteToWideChar(uCodePage, 0, str.c_str(), -1, NULL, 0);
		if (0 == nLength)
		{
			throw std::exception("A2W Error");
		}
		std::wstring strW(nLength, L'\0');
		int nResult = ::MultiByteToWideChar(uCodePage, 0, str.c_str(), -1, &strW[0], nLength);
		if (nResult != nLength)
		{
			throw std::exception("A2W Error");
		}
		strW.resize(nLength - 1);
		return strW;
	}

	/*!
	 * 宽字节转窄字节
	 * 
	 * \param str 宽字节
	 * \param uCodePage 窄字节编码
	 * \return 窄字节
	 */
	static std::string W2A(const std::wstring &str, UINT uCodePage)
	{
		int nLength = ::WideCharToMultiByte(uCodePage, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
		if (0 == nLength)
		{
			throw std::exception("W2A Error");
		}
		std::string strA(nLength, '\0');
		int nResult = ::WideCharToMultiByte(uCodePage, 0, str.c_str(), -1, &strA[0], nLength, NULL, NULL);
		if (nResult != nLength)
		{
			throw std::exception("W2A Error");
		}
		strA.resize(nLength - 1);
		return strA;
	}

	/*!
	 * 窄字节转窄字节
	 * 
	 * \param str 窄字节
	 * \param uCodePageFrom 源始字节编码
	 * \param uCodePageTo 目标字节编码
	 * \return 窄字节
	 */
	static std::string A2A(const std::string &str, UINT uCodePageFrom, UINT uCodePageTo)
	{
		return W2A(A2W(str, uCodePageFrom), uCodePageTo);
	}

	/*!
	 * 检查缓冲区数据是否是UTF-8
	 * 
	 * \param pBuffer 缓冲区
	 * \param size 大小
	 * \return 如果是返回true,否则返回false。
	 * 
	 * \note 返回结果并不一定完全正确,仅作为一个参考用途。
	 */
	static bool IsUTF8(const void* pBuffer, size_t size)
	{
		//参考 http://blog.csdn.net/bladeandmaster88/article/details/54767487
		bool bIsUTF8 = true;
		unsigned char* start = (unsigned char*)pBuffer;
		unsigned char* end = (unsigned char*)pBuffer + size;

		while (start < end)
		{
			if (*start < 0x80) // (10000000): 值小于0x80的为ASCII字符     
			{
				start++;
			}
			else if (*start < (0xC0)) // (11000000): 值介于0x80与0xC0之间的为无效UTF-8字符     
			{
				bIsUTF8 = false;
				break;
			}
			else if (*start < (0xE0)) // (11100000): 此范围内为2字节UTF-8字符     
			{
				if (start >= end - 1)
					break;

				if ((start[1] & (0xC0)) != 0x80)
				{
					bIsUTF8 = false;
					break;
				}
				start += 2;
			}
			else if (*start < (0xF0)) // (11110000): 此范围内为3字节UTF-8字符
			{
				if (start >= end - 2)
					break;

				if ((start[1] & (0xC0)) != 0x80 || (start[2] & (0xC0)) != 0x80)
				{
					bIsUTF8 = false;
					break;
				}
				start += 3;
			}
			else
			{
				bIsUTF8 = false;
				break;
			}
		}

		return bIsUTF8;
	}

	/*!
	* 检查字符串是不是UTF-8编码
	*
	* \param str 缓冲区
	* \return 如果是返回true,否则返回false。
	* 
	* \note 返回结果并不一定完全正确,仅作为一个参考用途。
	*/
	static bool IsUTF8(const std::string &str)
	{
		return IsUTF8(str.c_str(), str.size());
	}
}

//为了方便方便使用定义的宏
#define ANSI_TO_WCHAR(str)         (ZEncode::A2W(str, CP_ACP))
#define ANSI_TO_UTF8(str)          (ZEncode::A2A(str, CP_ACP, CP_UTF8))

#define UTF8_TO_ANSI(str)          (ZEncode::A2A(str, CP_UTF8, CP_ACP))
#define UTF8_TO_WCHAR(str)         (ZEncode::A2W(str, CP_UTF8))

#define WCHAR_TO_ANSI(str)         (ZEncode::W2A(str, CP_ACP))
#define WCHAR_TO_UTF8(str)         (ZEncode::W2A(str, CP_UTF8))

 

 测试用例(备注:Windows中文版环境[gb2312],Visual Studio默认文件编码[gb2312]):

/***** ZEncode *****/
namespace ZEncodeTest
{
	TEST(ZEncode, ansi_to_wchar_to_ansi)
	{
		std::string strANSI("中华人民共和国");
		std::wstring strWChar = ANSI_TO_WCHAR(strANSI);
		EXPECT_STREQ(strWChar.c_str(), L"中华人民共和国");
		EXPECT_STREQ(WCHAR_TO_ANSI(strWChar).c_str(), "中华人民共和国");
	}

	TEST(ZEncode, ansi_to_utf8_to_wchar)
	{
		std::string strANSI("中华人民共和国");
		std::string strUTF8 = ANSI_TO_UTF8(strANSI);
		EXPECT_FALSE(ZEncode::IsUTF8(strANSI));
		EXPECT_TRUE(ZEncode::IsUTF8(strUTF8));
		EXPECT_STREQ(UTF8_TO_WCHAR(strUTF8).c_str(), L"中华人民共和国");
	}

	TEST(ZEncode, ansi_to_utf8_to_ansi)
	{
		std::string strANSI("中华人民共和国");
		std::string strUTF8 = ANSI_TO_UTF8(strANSI);
		EXPECT_FALSE(ZEncode::IsUTF8(strANSI));
		EXPECT_TRUE(ZEncode::IsUTF8(strUTF8));
		EXPECT_STREQ(UTF8_TO_ANSI(strUTF8).c_str(), strANSI.c_str());
	}

	TEST(ZEncode, wchar_to_utf8_to_wchar)
	{
		std::wstring strWChar(L"中华人民共和国");
		std::string strUTF8 = WCHAR_TO_UTF8(strWChar);
		EXPECT_TRUE(ZEncode::IsUTF8(strUTF8));
		EXPECT_STREQ(UTF8_TO_WCHAR(strUTF8).c_str(), strWChar.c_str());
	}
}


  其它:在C++11中,如果希望初始化的字符串编码为utf-8,只需要在字符前面新增u8即可,如下:

std::string s1 = "中华人民共和国";  //取决于文件编码
std::string s2 = u8"中华人民共和国";  //utf-8编码

本站部分资源收集于网络,纯个人收藏,无商业用途,如有侵权请及时告知!

0
分享到:

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址