目录

1 编码    1

2 编码代码(C++)    2

3 解码代码(C++)    4

4 测试代码(VC++)    7

1 编码

UTF-7编码的规则及特点为:

1)UTF16小于等于 0x7F 的字符,采用ASCII编码;

2)UTF16大于0x7F的字符,采用Base64编码,然后在首尾分别加上+-;

3)UTF-7编码后,所有字符均小于等于 0x7F。

如字符串"A编码示例bC+123"的UTF-7编码为字符串"A+fxZ4AXk6T4s-bC+-123"。"+fxZ4AXk6T4s-"中的fxZ4AXk6T4s是"编码示例"的Base64编码;"+-"表示字符+;其余的保持不变。

以"编"为例,对Base64编码进行说明:

内容

说明

字符串

7F 16

UTF-16编码,高字节在前,16进制

0111 1111 0001 0110

UTF-16编码,高字节在前,2进制

011111 110001 011000

分组,6位一组,末尾补两个0

31 49 24

10进制

f x Y

根据10进制查下面的Base64编码表

下表是Base64编码表。

个位

十位

0

1

2

3

4

5

6

7

8

9

0

A

B

C

D

E

F

G

H

I

J

1

K

L

M

N

O

P

Q

R

S

T

2

U

V

W

X

Y

Z

a

b

c

d

3

e

f

g

h

i

j

k

l

m

n

4

o

p

q

r

s

t

u

v

w

x

5

y

z

0

1

2

3

4

5

6

7

6

8

9

+

/

           

上面"编"的Base64编码是"fxY",为什么"编码示例"的Base64编码是"fxZ4AXk6T4s"呢?因为fxZ中的Z既包含了"编"的编码信息,又包含了"码"的编码信息。这是UTF-7编码最复杂的地方。

2 编码代码(C++)

//Base64 编码字符串

const static char* s_Base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static void UTF16to7(std::string&s7,int&n,unsigned short code[8])

{

switch(n)

{

case 1://连续 1 个字符大于 7F

n = 3; //3 个 code[]

break;

case 2://连续 2 个字符大于 7F

n = 6; //6 个 code[]

break;

case 3://连续 3 个字符大于 7F

n = 8; //8 个 code[]

break;

default:

n = 0;

}

if(n)

{

for(int i = 0;i < n;++i)

{

s7 += s_Base64Table[code[i]];

}

n = 0;

}

}

/***************************************************************\

将 UTF-16 字符串转换为 UTF-7 字符串

pUTF16 [in] UTF-16 字符串首地址

nBytes [in] UTF-16 字符串字节数,即字符数 * 2

bLE [in] UTF-16 是否低位字节在前

返回:UTF-7 字符串

\***************************************************************/

std::string UTF16toUTF7(const void*pUTF16,unsigned long nBytes,bool bLE)

{

std::string s7;

if(pUTF16 && nBytes >= 2)

{

unsigned char* p16 = (unsigned char*)pUTF16;

unsigned short u16 = 0;

bool bCode = false; //是否正在编码

//编码的第几个字符 1、2、3、1、2、3……

int n = 0;

unsigned short code[8]; //编码的内容暂时存入此数组

for(unsigned long i = 1;i < nBytes;i += 2)

{

//计算当前字符 u16

if(bLE)

{//低位字节在前

u16 = p16[i - 1] | (p16[i] << 8);

}

else

{//高位字节在前

u16 = (p16[i - 1] << 8) | p16[i];

}

if(u16 <= 0x7F)

{//当前字符小于等于 7F

if(bCode)

{

if(n)

{

UTF16to7(s7,n,code);

}

s7 += '-';

bCode = false; //标记未在编码

}

s7 += (char)u16;

if(u16 == '+')

{

s7 += '-';

}

}

else

{//当前字符大于 7F

switch(++n)

{

case 1: //连续 1 个字符大于 7F

if(!bCode)

{//编码的第一个字符

s7 += '+';

}

code[0] = u16 >> 10;

code[1] = (u16 >> 4) & 63;

code[2] = (u16 << 2) & 63;

break;

case 2: //连续 2 个字符大于 7F

code[2] |= u16 >> 14;

code[3] = (u16 >> 8) & 63;

code[4] = (u16 >> 2) & 63;

code[5] = (u16 << 4) & 63;

break;

case 3: //连续 3 个字符大于 7F

code[5] |= u16 >> 12;

code[6] = (u16 >> 6) & 63;

code[7] = u16 & 63;

//每编码 3 个字符,将 code[8] 的内容加入 s7。同时 n 重新计数

UTF16to7(s7,n,code);

break;

}

bCode = true; //标记正在编码

}

}

if(bCode)

{

if(n)

{

UTF16to7(s7,n,code);

}

s7 += '-';

}

}

return s7;

}

3 解码代码(C++)

//判断某个字符是否为 Base64 编码,出错返回 0xFF

static char IsBase64Char(char c)

{

if(c)

{

const char*pFind = strchr(s_Base64Table,c);

if(pFind)

{

return pFind - s_Base64Table;

}

}

return '\xFF';

}

static void UTF7to16(std::string&s16,unsigned short c,bool bLE)

{

if(bLE)

{//低位字节在前

s16 += (char)c;

s16 += (char)(c >> 8);

}

else

{//高位字节在前

s16 += (char)(c >> 8);

s16 += (char)c;

}

}

/***************************************************************\

将 UTF-7 字符串转换为 UTF-16 字符串

pUTF7 [in] UTF-7 字符串首地址

nBytes [in] UTF-7 字符串字节数,即字符数 * 2

bLE [in] UTF-16 是否低位字节在前

返回:UTF-16 字符串

\***************************************************************/

std::string UTF7toUTF16(const void*pUTF7

,unsigned long nBytes,bool bLE)

{

std::string s16;

if(pUTF7 && nBytes)

{

unsigned char* p7 = (unsigned char*)pUTF7;

bool bCode = false; //是否正在解码状态

int n = 0; //解码的第几个字符,[0,7] 循环

unsigned short code[8]; //解码的结果暂时存入该数组

for(unsigned long i = 0;i < nBytes;++i)

{

if(bCode)

{//正在解码状态

if(p7[i] == '-')

{//停止解码

if(p7[i - 1] == '+')

{

UTF7to16(s16,'+',bLE);

}

bCode = false;

}

else

{

code[n] = IsBase64Char(p7[i]);

if(code[n] != 0xFF)

{

switch(++n)

{

case 3://1个字符

UTF7to16(s16

,(code[0] << 10) | (code[1] << 4) | (code[2] >> 2),bLE);

break;

case 6://2个字符

UTF7to16(s16

,(code[2] << 14) | (code[3] << 8) | (code[4] << 2) | (code[5] >> 4)

,bLE);

break;

case 8://3个字符

UTF7to16(s16

,(code[5] << 12) | (code[6] << 6) | code[7],bLE);

n = 0;

break;

}

}

}

}

else

{//不在解码状态

if(p7[i] == '+')

{//当前字符为 + 号

n = 0;

bCode = true; //标记处于解码状态

}

else

{

UTF7to16(s16,p7[i],bLE);

}

}

}

}

return s16;

}

4 测试代码(VC++)

const wchar_t* pUTF16LE = L"A编码示例bC+123";

//UTF16LE 转换为 UTF7,应返回A+fxZ4AXk6T4s-bC+-123

std::string sUTF7 = UTF16toUTF7(pUTF16LE,wcslen(pUTF16LE) * 2);

//UTF7 转换为 UTF16LE

std::string sUTF16LE = UTF7toUTF16(sUTF7.c_str(),sUTF7.length());

sUTF16LE += '\0'; //末尾添加一个 \0

//pUTF16LE 所指向的宽字符串,应该是"A编码示例bC+123"

pUTF16LE = (const wchar_t*)sUTF16LE.c_str();

UTF-7编码的更多相关文章

  1. 从Java String实例来理解ANSI、Unicode、BMP、UTF等编码概念

    转(http://www.codeceo.com/article/java-string-ansi-unicode-bmp-utf.html#0-tsina-1-10971-397232819ff9a ...

  2. 文字编码ASCII,GB2312,GBK,GB18030,UNICODE,UCS,UTF的解析

    众所周知,一个文字从输入到显示到存储是有一个固定过程的,其过程为:输入码(根据输入法不同而不同)→机内码(根据语言环境不同而不同,不同的系统语言编码也不一样)→字型码(根据不同的字体而不同)→存储码( ...

  3. 字符集、字符编码、国际化、本地化简要总结(UNICODE/UTF/ASCII/GB2312/GBK/GB18030)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 环境说明   普通的linux 和 普通的windows.    ...

  4. Python里的编码问题

    马克一篇 http://bbs.chinaunix.net/archiver/tid-1163613.html http://www.openhome.cc/Gossip/Python/ImportI ...

  5. JAVA基础学习day22--IO流四-对象序列化、管道流、RandomAccessFile、DataStream、ByteArrayStream、转换流的字符编码

    一.对象序列化 1.1.对象序列化 被操作的对象需要实现Serializable接口 1.2.对象序列化流ObjectOutputStream与ObjectInputStream ObjectInpu ...

  6. Java中常用的字符编码-解析

    ASCII字符编码 美国信息互换标准代码,为罗马字母编制的一套编码,主要用于表达现代英语和其他西欧语言中的字符,1字节的7位表示一个字符. ISO-8859-1字符编码 ISO为西欧语言中的字符制定的 ...

  7. 请问什么是UTF字符串?

    utf是编码方式,一般而言是国际性质的编码格式,有utf-8,utf-9,utf-16等多种形式,是最高级别的编码方式,也就是说如果你要读取的数据流设置成utf编码的话就要用到相应的编码方式来读取了, ...

  8. python之路--day6--字符编码

    一.知识储备 cpu--控制和运算 内存--暂时存储cpu需要的数据 硬盘--永久保存数据2.文本编辑器的原理存储原理 1,启动文本编辑器 2,在编辑器上输入内容---此时输入内容还在内存上 3,保存 ...

  9. 关于烦躁的网页编码问题utf-8,gb2312。终于自己实践了一遍

    俗话说实践是检验真理的唯一标准,的确如此. 自己一直比较懒,虽然觉得大牛应该一个记事本全部搞定,但自己还是喜欢用Dw或者Vs写好网页的架构,因为总觉得用notepad还要自己导入声明,而gVim还没有 ...

  10. Unicode字符集和UTF-8, UTF-16, UTF-32编码

    ASCII 在过去的计算中,ASCII码被用来表示字符.英语只有26个字母和其他一些特殊字符和符号. 下表提供了ASCII字符及其相应的十进制和十六进制值. 可以从上面的表中推断,在十进制数系统中,A ...

随机推荐

  1. Android 编程下Touch 事件的分发和消费机制

    1.事件分发:public boolean dispatchTouchEvent(MotionEvent ev) Touch 事件发生时 Activity 的 dispatchTouchEvent(M ...

  2. 查看centos是多少位的系统命令

    打开命令行 运行下面命令 uname -i 如果是64位系统会显示x86_64 如果显示的是i386则是系统是32位

  3. CentOS6.5下安装wine OK

    这篇文章主要记录了如何在CentOS 6.5上安装Wine 1.7.24开发版 1.安装需要的软件包 # yum groupinstall ‘Development Tools‘ # yum inst ...

  4. Infragistics 汉化

    Infragistics 汉化实例: Infragistics.Shared.ResourceCustomizer rc=Infragistics.Win.UltraWinGrid.Resources ...

  5. 【Java】List集合按数量分组

    有时候,我们需要将大的集合按指定的数量分割成若干个小集合.(比如:集合作为SQL中IN的参数,而SQL又有长度限制,所以需要分批分几次进行查询) 虽然此需求感觉不常见,但偶也写过几次类似的方法,故记录 ...

  6. Fragment懒加载

    package com.bpj.lazyfragment;import android.support.v4.app.Fragment;/* *baseFragment */ public class ...

  7. 5-JS函数

    函数 定义函数 JS中有3种定义函数的方法: 函数声明 用函数声明定义函数的方式如下: function abs(x) { if (x >= 0) { return x; } else { re ...

  8. raid0,raid1,raid10,raid5,raid50,raid6,raid60的功能总结简述

    1,raid0的特性:采用剥离,数据将在几个磁盘上进行分割.数据被分成很多数据块,每一数据块会被写入不同的磁盘.从而, 每一磁盘的工作负荷都得到了降低,这有助于加速数据传输.RAID-0可让磁盘更好地 ...

  9. 友情提醒:欲开发android5.0以上应用,请全部更新开发工具至最新

    周末帮人完成一个项目,android5.0以上版本,谁知道被开发工具折腾的死去活来.我的开发环境是adt-bundle-windows-x86-20140702.zip版本,也是目前能找到的adt-b ...

  10. web应用中web.xml配置详解

    Web.xml常用元素 <web-app> <display-name></display-name>定义了WEB应用的名字 <description> ...