ASCII/UNICODE/UTF8字符串互相转换的C++代码

时间:2023-01-10 15:36:52

这是一个我写的类,用来在这多种字符串之间转换,另外还有一些用于由.net支持的时候在.net字符串String^与标准C++字符串之间相互转换的函数。请原谅我为了复用将其放到了dbsoft这样一个命名空间中。下面是使用它的简单示例:

#include <iostream>
#include <string>
#include <locale>
using namespace std;

#include <dbsoft/generic/string_shim.hpp>

using namespace dbsoft;

#define PRINT( OSTREAM, exp ) \
OSTREAM<< #OSTREAM <<" test->>> "<< #exp <<" : " << exp << endl << endl

int main()
{
const char* pAsciiStr = "地址:http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2";
const wchar_t* pUnicodeStr = L"地址:http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2";

cout << "ASCII: "<< pAsciiStr << endl;

// 确保在简体中文操作系统上能够正确的输出中文,因此需要设置本地化
wcout.imbue( locale("chs") );
wcout <<L"UNICODE: "<< pUnicodeStr << endl;

cout<<"--------------------------------- 分割线 ----------------------------------\n";

// 将UNICODE转换为 ASCII
PRINT( cout, DBSOFT_CAST_TO_CHAR_STR( pUnicodeStr ) );

// 将ASCII转换为UNICODE
PRINT( wcout, DBSOFT_CAST_TO_WCHAR_STR( pAsciiStr ) );

// 将ASCII转换到UTF8
std::basic_string< dbsoft::utf8_char > strUtf8 = dbsoft::string_shim< dbsoft::utf8_char >( pAsciiStr ).toStlStr();

// 将UTF8转换为ASCII
PRINT( cout, dbsoft::string_shim<char>( strUtf8.c_str() ).toStr() );

// 将UTF8转换为UNICODE
PRINT( wcout, dbsoft::string_shim<wchar_t>( strUtf8.c_str() ).toStr() );

return 0;
}

       主要有两种使用方式,其一是直接使用我预定义好的宏,其二是显式的使用模板类来转换,实际上都是一样,宏的好处就在于更明显一点吧。另外将UTF8约定为unsigned char。

       对于UTF8,我曾经用这个类来处理UTF8编码的MP3文件,暂时没有发现什么问题。也能正确的将以UTF8编码存储在MP3文件中的内容读取出来,包括汉字。

       代码中我上色的部分是大家如果要使用的话可能需要修改的,因为目录和位置毕竟不同。由于除了这个组件之外,dbsoft还剩余其它很多东西,所以我没把这些代码剥离出来,所以请大家凑合凑合吧。

       输出:

ASCII: 地址:http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2
UNICODE: 地址:http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2
--------------------------------- 分割线 ----------------------------------
cout test->>> DBSOFT_CAST_TO_CHAR_STR( pUnicodeStr ) : 地址:http://hi.baidu.com/
_%E2d_%B7%B3_%DE%B2%C2%D2

wcout test->>> DBSOFT_CAST_TO_WCHAR_STR( pAsciiStr ) : 地址:http://hi.baidu.com/
_%E2d_%B7%B3_%DE%B2%C2%D2

cout test->>> dbsoft::string_shim<char>( strUtf8.c_str() ).toStr() : 地址:http:/
/hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2

wcout test->>> dbsoft::string_shim<wchar_t>( strUtf8.c_str() ).toStr() : 地址:ht
tp://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2

请按任意键继续. . .

ASCII/UNICODE/UTF8字符串互相转换的C++代码

      代码:

/**
* @brief 字符串编码转换类
* @author dongbo
* @date 2010.3.16
*/

#pragma once

#include "noncopyable.hpp"

#include <windows.h> 
#include <string> 
#include <cassert>

namespace dbsoft
{
typedef unsigned char utf8_char;

/**
* @brief 字符串转换所用
* @remaks 如果你想得到某种字符的字符串,只需要使用任何一种字符串作为参数去构建目标字符串编码类型特化的string_shim
*      然后使用它的方法就可以直接得到目标字符串了
*/
template < typename _TC > 
class string_shim : private noncopyable

public: 
   typedef _TC    char_type; 
};

/**
* @brief 使用各种字符串来构造它,就可以得到wchar_t的字符串类型
*/
template <> 
class string_shim<wchar_t> : private noncopyable 

public: 
   typedef wchar_t                          char_type;
   typedef std::basic_string<char_type>     stl_string;
public: 
   ~string_shim() 
   { 
    if( NULL != m_pBuf ) 
    { 
     delete[] m_pBuf; 
     m_pBuf = NULL; 
    } 
   }

   string_shim( const char* str ):m_pBuf(NULL) 
   {   
    this->doConvert( str ); 
   }

   string_shim( const std::string& str ):m_pBuf(NULL) 
   {   
    this->doConvert( str.c_str(), (int)str.size() ); 
   }

   string_shim( const utf8_char* pUtf8 ):m_pBuf(NULL)
   {
    assert( pUtf8 != NULL && "源数据不可为空" );

    // 这里是字节数而不是字符串个数 计算长度用_mbslen,计算字节数还是用strlen好了
    unsigned uUtf8Len = (unsigned)strlen((const char*)pUtf8);
   
    int uLen = ::MultiByteToWideChar( CP_UTF8, NULL, (char*)pUtf8, uUtf8Len, NULL, 0 );

    m_pBuf = new char_type[uLen + 1];
    ::ZeroMemory( m_pBuf, uLen + 1);
    ::MultiByteToWideChar( CP_UTF8, NULL, (char*)pUtf8, uUtf8Len, m_pBuf, uLen );
    m_pBuf[uLen] = 0;
   }

public: 
   // 操作 
   inline const char_type* toStr() const 
   { 
    return this->m_pBuf; 
   } 
   inline stl_string toStlStr() const 
   { 
    return this->m_pBuf; 
   }

private: 
   inline void doConvert( const char* str, int iLen = -1 ) 
   { 
    assert( str && "被转换的字符串不可为空!" );

    if( -1 == iLen ) 
    { 
     iLen = (int)strlen( str ); 
    } 
    int iLength = ::MultiByteToWideChar( CP_ACP, 0, 
     str, iLen, NULL, 0 ); 
    m_pBuf = new wchar_t[iLength+1]; 
    ::MultiByteToWideChar( CP_ACP, 0, str, iLen, m_pBuf, iLength ); 
    m_pBuf[iLength] = L'\0'; 
   } 
private: 
   char_type*       m_pBuf; 
};

/**
* @brief 使用各种字符串来构造它,就可以得到char的字符串类型
*/
template <> 
class string_shim<char> : private noncopyable 

public: 
   typedef char                              char_type; 
   typedef std::basic_string<char_type>      stl_string;
public: 
   ~string_shim() 
   { 
    if( NULL != m_pBuf ) 
    { 
     delete[] m_pBuf; 
     m_pBuf = NULL; 
    } 
   }

   string_shim( const wchar_t* wstr ):m_pBuf(NULL) 
   { 
    this->doConvert( wstr ); 
   } 
   string_shim( const std::wstring& wstr ):m_pBuf(NULL) 
   { 
    this->doConvert( wstr.c_str(), (int)wstr.size() ); 
   }

   string_shim( const utf8_char* pStr ):m_pBuf(NULL)
   {
    string_shim<wchar_t> shim(pStr);

    this->doConvert( shim.toStr() );
   }

public: 
   inline const char_type* toStr() const 
   { 
    return m_pBuf; 
   } 
   inline stl_string toStlStr() const 
   { 
    return m_pBuf; 
   } 
private: 
   inline void doConvert( const wchar_t* wstr, int iLen = -1 ) 
   { 
    assert( wstr && "目标字符串不能为空" ); 
    if( -1 == iLen ) 
    { 
     iLen = static_cast<unsigned>(wcslen( wstr )); 
    }

    int iLength = ::WideCharToMultiByte( 0, 0, wstr, iLen, NULL, 0, NULL, NULL ); 
    ++iLength; 
    m_pBuf = new char[iLength]; 
    ::WideCharToMultiByte( 0, 0, wstr, iLen, m_pBuf, iLength, NULL, NULL ); 
    m_pBuf[iLength-1] = '\0'; 
   } 
private: 
   char_type*       m_pBuf; 
};

/**
* @brief 使用各种字符串来构造它,就可以得到utf8的字符串类型
*/
template <>
class string_shim<utf8_char> : private noncopyable
{
public:
   typedef utf8_char                        char_type;
   typedef std::basic_string< utf8_char >   stl_string;
public:
   ~string_shim() 
   { 
    if( NULL != m_pBuf ) 
    { 
     delete[] m_pBuf; 
     m_pBuf = NULL; 
    } 
   }

public:
   string_shim( const char_type* str ):m_pBuf(NULL)
   {
    assert( str != NULL && "源数据不可为空" );

    unsigned uLen = (unsigned)strlen((const char*)str);
    m_pBuf = new char_type[uLen +1 ];
    ::ZeroMemory( m_pBuf, uLen + 1);
    ::memcpy_s( m_pBuf, uLen, str, uLen );
    m_pBuf[uLen] = 0;
   }

   string_shim( const char* str ):m_pBuf(NULL)
   {
    assert( str != NULL && "源数据不可为空" );

    string_shim<wchar_t> shim(str);
    this->doCopy( shim.toStr() );
   }

   string_shim( const wchar_t* pUniStr ):m_pBuf(NULL)
   {
    this->doCopy( pUniStr );
   }

public:
   inline const char_type* toStr() const
   {
    if( m_pBuf != NULL )
    {
     return m_pBuf;
    }

    static const char_type s_Buf[]= {0};

    return s_Buf;   
   }  

   inline stl_string toStlStr() const
   {
    return this->toStr();
   }

protected:
   void doCopy( const wchar_t* pszUniStr )
   {
    if( pszUniStr == NULL )
    {
     return;
    }
    unsigned uUniLen = (unsigned)wcslen(pszUniStr);

    int uLen = ::WideCharToMultiByte( CP_UTF8, NULL, pszUniStr, uUniLen, NULL, 0, NULL, NULL );
    if( uLen < 0 )
    {
     return;
    }

    m_pBuf = new char_type[ uLen + 1];

    ::WideCharToMultiByte(CP_UTF8, NULL, pszUniStr, uUniLen, (LPSTR)m_pBuf, uLen, NULL, NULL );
    m_pBuf[uLen] = 0;
   }

private:
   char_type* m_pBuf;
};

#define DBSOFT_CAST_TO_UTF8_STR( str ) \
dbsoft::string_shim< dbsoft::utf8_char >( str ).toStr()

#define DBSOFT_CAST_TO_UTF8_STRING( str ) \
dbsoft::string_shim< dbsoft::utf8_char >( str ).toStlStr()

#define DBSOFT_CAST_TO_CHAR_STR( str ) \
dbsoft::string_shim< char >( str ).toStr()

#define DBSOFT_CAST_TO_CHAR_STRING( str ) \
dbsoft::string_shim< char >( str ).toStlStr()

#define DBSOFT_CAST_TO_WCHAR_STR( str ) \
dbsoft::string_shim< wchar_t >( str ).toStr()

#define DBSOFT_CAST_TO_WCHAR_STRING( str ) \
dbsoft::string_shim< wchar_t >( str ).toStlStr();
}


#ifdef __cplusplus_cli
#include <vcclr.h>

namespace dbsoft
{
namespace clrtool
{
   inline std::wstring Cast_CliStr_To_WString( System::String^ hString )
   {
    if( nullptr == hString )
    {
     return L"";
    }

    pin_ptr< const wchar_t > pinnedStr = ::PtrToStringChars( hString );

    std::wstring strResult = pinnedStr;

    return strResult;
   }

   inline std::string Cast_CliStr_To_String( System::String^ hString )
   {
    return dbsoft::string_shim<char>( Cast_CliStr_To_WString(hString) ).toStlStr();
   }

   inline System::String^ Cast_WStr_To_CliString( const std::wstring& strUniStr )
   {
    return gcnew System::String( strUniStr.c_str(), 0, strUniStr.size() );
   }

   inline System::String^ Cast_Str_To_CliString( const std::string& strAnsiStr )
   {
    return Cast_WStr_To_CliString( dbsoft::string_shim<wchar_t>( strAnsiStr ).toStlStr() );
   }
}
}

#endif

/// 另外一个辅助类

/**
* @brief   用于不可复制的类的基类 比如单件
* @author dongbo
* @date    2010-3-15
* @remarks
**/

#pragma once

namespace dbsoft
{
class noncopyable
{
protected:
   noncopyable() {}
   ~noncopyable() {}
private: 
   noncopyable( const noncopyable& );
   const noncopyable& operator=( const noncopyable& );
};
}

PS:辅助搜索标签:C++ ASCII转UNICODE UNICODE转ASCII UNICODE转UTF8 UTF8转UNICODE UTF8转ASCII。

2010.5.6 Patch1:

/**
* @brief 字符串编码转换类
* @author dongbo
* @date 2010.3.16
*/

#pragma once

#include "noncopyable.hpp"

#include <windows.h> 
#include <string> 
#include <cassert>

namespace dbsoft
{
typedef unsigned char utf8_char;

/**
* @brief 字符串转换所用
* @remaks 如果你想得到某种字符的字符串,只需要使用任何一种字符串作为参数去构建目标字符串编码类型特化的string_shim
*      然后使用它的方法就可以直接得到目标字符串了
*/
template < typename _TC > 
class string_shim : private noncopyable

public: 
   typedef _TC    char_type; 
};

/**
* @brief 使用各种字符串来构造它,就可以得到wchar_t的字符串类型
*/
template <> 
class string_shim<wchar_t> : private noncopyable 

public: 
   typedef wchar_t                          char_type;
   typedef std::basic_string<char_type>     stl_string;
public: 
   ~string_shim() 
   { 
    if( NULL != m_pBuf ) 
    { 
     delete[] m_pBuf; 
     m_pBuf = NULL; 
    } 
   }

   string_shim( const char* str ):m_pBuf(NULL) 
   {   
    this->doConvert( str ); 
   }

   string_shim( const std::string& str ):m_pBuf(NULL) 
   {   
    this->doConvert( str.c_str(), (int)str.size() ); 
   }

   string_shim( const wchar_t* pWStr ):m_pBuf(NULL)
   {
    size_t uLen = wcslen( pWStr );
    m_pBuf = new wchar_t[uLen+1];
    wcscpy_s( m_pBuf, uLen+1, pWStr );
   }

   string_shim( const std::wstring& strWStr ):m_pBuf(NULL)
   {
    m_pBuf = new wchar_t[strWStr.size()+1];
    wcscpy_s( m_pBuf, strWStr.size()+1, strWStr.c_str() );
   }

   string_shim( const utf8_char* pUtf8 ):m_pBuf(NULL)
   {
    assert( pUtf8 != NULL && "源数据不可为空" );

    // 这里是字节数而不是字符串个数 计算长度用_mbslen,计算字节数还是用strlen好了
    unsigned uUtf8Len = (unsigned)strlen((const char*)pUtf8);
   
    int uLen = ::MultiByteToWideChar( CP_UTF8, NULL, (char*)pUtf8, uUtf8Len, NULL, 0 );

    m_pBuf = new char_type[uLen + 1];
    ::ZeroMemory( m_pBuf, uLen + 1);
    ::MultiByteToWideChar( CP_UTF8, NULL, (char*)pUtf8, uUtf8Len, m_pBuf, uLen );
    m_pBuf[uLen] = 0;
   }

public: 
   // 操作 
   inline const char_type* toStr() const 
   { 
    return this->m_pBuf; 
   } 
   inline stl_string toStlStr() const 
   { 
    return this->m_pBuf; 
   }

private: 
   inline void doConvert( const char* str, int iLen = -1 ) 
   { 
    assert( str && "被转换的字符串不可为空!" );

    if( -1 == iLen ) 
    { 
     iLen = (int)strlen( str ); 
    } 
    int iLength = ::MultiByteToWideChar( CP_ACP, 0, 
     str, iLen, NULL, 0 ); 
    m_pBuf = new wchar_t[iLength+1]; 
    ::MultiByteToWideChar( CP_ACP, 0, str, iLen, m_pBuf, iLength ); 
    m_pBuf[iLength] = L'\0'; 
   } 
private: 
   char_type*       m_pBuf; 
};

/**
* @brief 使用各种字符串来构造它,就可以得到char的字符串类型
*/
template <> 
class string_shim<char> : private noncopyable 

public: 
   typedef char                              char_type; 
   typedef std::basic_string<char_type>      stl_string;
public: 
   ~string_shim() 
   { 
    if( NULL != m_pBuf ) 
    { 
     delete[] m_pBuf; 
     m_pBuf = NULL; 
    } 
   }

   string_shim( const wchar_t* wstr ):m_pBuf(NULL) 
   { 
    this->doConvert( wstr ); 
   } 
   string_shim( const std::wstring& wstr ):m_pBuf(NULL) 
   { 
    this->doConvert( wstr.c_str(), (int)wstr.size() ); 
   }

   string_shim( const char* pStr ):m_pBuf(NULL)
   {
    size_t uLen = strlen( pStr );
    m_pBuf = new char_type[ uLen + 1 ];
    strcpy_s( m_pBuf, uLen + 1, pStr );
   }

   string_shim( const std::string& str ):m_pBuf(NULL)
   {
    m_pBuf = new char_type[ str.size() + 1 ];
    strcpy_s( m_pBuf, str.size() + 1, str.c_str() );
   }

   string_shim( const utf8_char* pStr ):m_pBuf(NULL)
   {
    string_shim<wchar_t> shim(pStr);

    this->doConvert( shim.toStr() );
   }

public: 
   inline const char_type* toStr() const 
   { 
    return m_pBuf; 
   } 
   inline stl_string toStlStr() const 
   { 
    return m_pBuf; 
   } 
private: 
   inline void doConvert( const wchar_t* wstr, int iLen = -1 ) 
   { 
    assert( wstr && "目标字符串不能为空" ); 
    if( -1 == iLen ) 
    { 
     iLen = static_cast<unsigned>(wcslen( wstr )); 
    }

    int iLength = ::WideCharToMultiByte( 0, 0, wstr, iLen, NULL, 0, NULL, NULL ); 
    ++iLength; 
    m_pBuf = new char[iLength]; 
    ::WideCharToMultiByte( 0, 0, wstr, iLen, m_pBuf, iLength, NULL, NULL ); 
    m_pBuf[iLength-1] = '\0'; 
   } 
private: 
   char_type*       m_pBuf; 
};

/**
* @brief 使用各种字符串来构造它,就可以得到utf8的字符串类型
*/
template <>
class string_shim<utf8_char> : private noncopyable
{
public:
   typedef utf8_char                        char_type;
   typedef std::basic_string< utf8_char >   stl_string;
public:
   ~string_shim() 
   { 
    if( NULL != m_pBuf ) 
    { 
     delete[] m_pBuf; 
     m_pBuf = NULL; 
    } 
   }

public:
   string_shim( const char_type* str ):m_pBuf(NULL)
   {
    assert( str != NULL && "源数据不可为空" );

    unsigned uLen = (unsigned)strlen((const char*)str);
    m_pBuf = new char_type[uLen +1 ];
    ::ZeroMemory( m_pBuf, uLen + 1);
    ::memcpy_s( m_pBuf, uLen, str, uLen );
    m_pBuf[uLen] = 0;
   }

   string_shim( const char* str ):m_pBuf(NULL)
   {
    assert( str != NULL && "源数据不可为空" );

    string_shim<wchar_t> shim(str);
    this->doCopy( shim.toStr() );
   }

   string_shim( const wchar_t* pUniStr ):m_pBuf(NULL)
   {
    this->doCopy( pUniStr );
   }

public:
   inline const char_type* toStr() const
   {
    if( m_pBuf != NULL )
    {
     return m_pBuf;
    }

    static const char_type s_Buf[]= {0};

    return s_Buf;   
   }  

   inline stl_string toStlStr() const
   {
    return this->toStr();
   }

protected:
   void doCopy( const wchar_t* pszUniStr )
   {
    if( pszUniStr == NULL )
    {
     return;
    }
    unsigned uUniLen = (unsigned)wcslen(pszUniStr);

    int uLen = ::WideCharToMultiByte( CP_UTF8, NULL, pszUniStr, uUniLen, NULL, 0, NULL, NULL );
    if( uLen < 0 )
    {
     return;
    }

    m_pBuf = new char_type[ uLen + 1];

    ::WideCharToMultiByte(CP_UTF8, NULL, pszUniStr, uUniLen, (LPSTR)m_pBuf, uLen, NULL, NULL );
    m_pBuf[uLen] = 0;
   }

private:
   char_type* m_pBuf;
};

#define DBSOFT_CAST_TO_UTF8_STR( str ) \
dbsoft::string_shim< dbsoft::utf8_char >( str ).toStr()

#define DBSOFT_CAST_TO_UTF8_STRING( str ) \
dbsoft::string_shim< dbsoft::utf8_char >( str ).toStlStr()

#define DBSOFT_CAST_TO_CHAR_STR( str ) \
dbsoft::string_shim< char >( str ).toStr()

#define DBSOFT_CAST_TO_CHAR_STRING( str ) \
dbsoft::string_shim< char >( str ).toStlStr()

#define DBSOFT_CAST_TO_WCHAR_STR( str ) \
dbsoft::string_shim< wchar_t >( str ).toStr()

#define DBSOFT_CAST_TO_WCHAR_STRING( str ) \
dbsoft::string_shim< wchar_t >( str ).toStlStr();
}


#ifdef __cplusplus_cli
#include <vcclr.h>

namespace dbsoft
{
namespace clrtool
{
   inline std::wstring Cast_CliStr_To_WString( System::String^ hString )
   {
    if( nullptr == hString )
    {
     return L"";
    }

    pin_ptr< const wchar_t > pinnedStr = ::PtrToStringChars( hString );

    std::wstring strResult = pinnedStr;

    return strResult;
   }

   inline std::string Cast_CliStr_To_String( System::String^ hString )
   {
    return dbsoft::string_shim<char>( Cast_CliStr_To_WString(hString) ).toStlStr();
   }

   inline System::String^ Cast_WStr_To_CliString( const std::wstring& strUniStr )
   {
    return gcnew System::String( strUniStr.c_str(), 0, strUniStr.size() );
   }

   inline System::String^ Cast_Str_To_CliString( const std::string& strAnsiStr )
   {
    return Cast_WStr_To_CliString( dbsoft::string_shim<wchar_t>( strAnsiStr ).toStlStr() );
   }
}
}

#endif


转自原创http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2/blog/item/a15b09662d887128aa184c35.html