C++ UTF8和UTF16互轉代碼
阿新 • • 發佈:2017-07-06
define iter 般的 != ont for efault 互轉 小端
簡介
1、這段代碼只考慮在小端序情況下的轉換(一般的機器都是的)。
2、這段代碼需要C++11的支持(只是用到了u16string
),如果不支持,可以添加下面代碼
typedef uint16_t char16_t;
typedef std::basic_string<char16_t>
utfconvert.h
#ifndef __UTFCONVERT_H__
#define __UTFCONVERT_H__
#include <string>
// 從UTF16編碼字符串構建,需要帶BOM標記
std::string utf16_to_utf8(const std::u16string& u16str);
// 從UTF16 LE編碼的字符串創建
std::string utf16le_to_utf8(const std::u16string& u16str);
// 從UTF16BE編碼字符串創建
std::string utf16be_to_utf8(const std::u16string& u16str);
// 獲取轉換為UTF-16 LE編碼的字符串
std::u16string utf8_to_utf16le(const std::string& u8str, bool addbom = false, bool* ok = NULL);
// 獲取轉換為UTF-16 BE的字符串
std::u16string utf8_to_utf16be(const std::string& u8str, bool addbom = false, bool* ok = NULL);
#endif //! __UTFCONVERT_H__
utfconvert.cpp
#include "utfconvert.h"
#include <stdint.h>
#ifdef __GNUC__
#include <endian.h>
#endif // __GNUC__
static inline uint16_t byteswap_ushort(uint16_t number)
{
#if defined(_MSC_VER) && _MSC_VER > 1310
return _byteswap_ushort(number);
#elif defined(__GNUC__)
return __builtin_bswap16(number);
#else
return (number >> 8) | (number << 8);
#endif
}
////////////////////////////////////////
// 以下轉換都是在小端序下進行 //
////////////////////////////////////////
// 從UTF16編碼字符串構建,需要帶BOM標記
std::string utf16_to_utf8(const std::u16string& u16str)
{
if (u16str.empty()){ return std::string(); }
//Byte Order Mark
char16_t bom = u16str[0];
switch (bom){
case 0xFEFF: //Little Endian
return utf16le_to_utf8(u16str);
break;
case 0xFFFE: //Big Endian
return utf16be_to_utf8(u16str);
break;
default:
return std::string();
}
}
// 從UTF16 LE編碼的字符串創建
std::string utf16le_to_utf8(const std::u16string& u16str)
{
if (u16str.empty()){ return std::string(); }
const char16_t* p = u16str.data();
std::u16string::size_type len = u16str.length();
if (p[0] == 0xFEFF){
p += 1; //帶有bom標記,後移
len -= 1;
}
// 開始轉換
std::string u8str;
u8str.reserve(len * 3);
char16_t u16char;
for (std::u16string::size_type i = 0; i < len; ++i){
// 這裏假設是在小端序下(大端序不適用)
u16char = p[i];
// 1字節表示部分
if (u16char < 0x0080){
// u16char <= 0x007f
// U- 0000 0000 ~ 0000 07ff : 0xxx xxxx
u8str.push_back((char)(u16char & 0x00FF)); // 取低8bit
continue;
}
// 2 字節能表示部分
if (u16char >= 0x0080 && u16char <= 0x07FF){
// * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
u8str.push_back((char)(((u16char >> 6) & 0x1F) | 0xC0));
u8str.push_back((char)((u16char & 0x3F) | 0x80));
continue;
}
// 代理項對部分(4字節表示)
if (u16char >= 0xD800 && u16char <= 0xDBFF) {
// * U-00010000 - U-001FFFFF: 1111 0xxx 10xxxxxx 10xxxxxx 10xxxxxx
uint32_t highSur = u16char;
uint32_t lowSur = p[++i];
// 從代理項對到UNICODE代碼點轉換
// 1、從高代理項減去0xD800,獲取有效10bit
// 2、從低代理項減去0xDC00,獲取有效10bit
// 3、加上0x10000,獲取UNICODE代碼點值
uint32_t codePoint = highSur - 0xD800;
codePoint <<= 10;
codePoint |= lowSur - 0xDC00;
codePoint += 0x10000;
// 轉為4字節UTF8編碼表示
u8str.push_back((char)((codePoint >> 18) | 0xF0));
u8str.push_back((char)(((codePoint >> 12) & 0x3F) | 0x80));
u8str.push_back((char)(((codePoint >> 06) & 0x3F) | 0x80));
u8str.push_back((char)((codePoint & 0x3F) | 0x80));
continue;
}
// 3 字節表示部分
{