真正UTF-8与GB2312间的转换(兼容windows和Linux)

                                                       UTF-8与GB2312间的转换
                                                               作者:曾刘彬
中文转码是程序员可能经常遇到的一个问题,鄙人在这方面有些心得,故在此抛砖引玉了。
    我在网上看到好多关于UTF-8与BG2312间互相转换都用一下的方法(为了方便,以后我称之为“拼凑法”):
  // 把UTF-8转换成Unicode
      void CChineseCodeLib::UTF_8ToUnicode(WCHAR* pOut,char *pText)
      {
          char* uchar = (char *)pOut;
    
          uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F);
          uchar[0] = ((pText[1] & 0x03) << 6) + (pText[2] & 0x3F);
    
          return;
      }
  // Unicode 转换成UTF-8
  void CChineseCodeLib::UnicodeToUTF_8(char* pOut,WCHAR* pText)
  {
     // 注意 WCHAR高低字的顺序,低字节在前,高字节在后
      char* pchar = (char *)pText;

     pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4));
     pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6);
     pOut[2] = (0x80 | (pchar[0] & 0x3F));
     return;
  }
    “拼凑法”可以成功的转换大部分的UTF-8编码,不过作为一个负责的人,我想指出其中的缺陷:
    真正的UTF-8的编码规则如下:
 U-00000000 - U-0000007F: 0xxxxxxx   
 U-00000080 - U-000007FF: 110xxxxx 10xxxxxx   
 U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx   
 U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx   
 U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx   
 U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 

        可见UTF-8 编码字符理论上可以是1 - 6 个字节长,而“拼凑法”只处理了1字节和3字节两种编码方式。有的人可能会说:16 位 BMP 字符最多只用到 3 字节长。这没错,拼凑发也没处理2字节编码方式。所以我得出结论:“拼凑法”是不安全的。
        言归正传,其实UTF-8与GB2312之间的转化不用弄得那么复杂。
        在windows下用这两个现成的函数,通过不同的参数就能实现。   
            ::WideCharToMultiByte(。。。)   
            ::MultiByteToWideChar(。。。)
        若在Linux下,则用iconv命令实现。 具体代码如下:
        如果是windows下,则:#define __cdn_win32_platform__
#define CP_GB2312 20936
class CodingTransformer {
public:
 //GB2312 转为 UTF-8
 int  UTF_8ToGB2312(char* pOut, int iBufSize, char *pText, int iLenth);
 //GB2312 转为 UTF-8
 int  GB2312ToUTF_8(char* pOut, int iBufSize,char *pText, int iLenth);
};
int CodingTransformer::UTF_8ToGB2312(char* pOut, int iBufSize, char *pText, int pLen)
{
#ifdef __cdn_win32_platform__
 WCHAR* pWtemp = new WCHAR[pLen];
 int iWcharLenth = ::MultiByteToWideChar(CP_UTF8,0,pText,-1,pWtemp,pLen); 
 if (0 == iWcharLenth)
 {
  DWORD dwLastErr = GetLastError();
  printf("alexaroma:转码错误,错误号:%d/n", dwLastErr);
  delete pWtemp;
  return 0;
 }
 int iMultByteLenth = ::WideCharToMultiByte(CP_GB2312, NULL, pWtemp,
                                         iWcharLenth, pOut,
              iBufSize, NULL, NULL);
 if (0 == iMultByteLenth)
 {
  DWORD dwLastErr = GetLastError();
  printf("alexaroma:转码错误,错误号:%d/n", dwLastErr);
  delete pWtemp;
  return 0;
 }
 delete pWtemp;
 return iMultByteLenth;
#else//__cdn_win32_platform__
 iconv_t cd;
 int rc;
 char   **pin   =   &pText;
 char   **pout   =   &pOut;
 int outlen = iBufSize;
 cd   =   iconv_open("GB2312","UTF-8");
 if(cd==0)return -1;
 memset(pOut,0,strlen(pOut));
 if(iconv(cd,pin,(size_t   *)&pLen,pout,(size_t   *)&outlen) == -1)
 {
  iconv_close(cd);
  return outlen;
 }
 iconv_close(cd);
 return -1;
#endif//__cdn_win32_platform__
}
int  CodingTransformer::GB2312ToUTF_8(char* pOut, int iBufSize,
           char *pText, int pLen)
{
#ifdef __cdn_win32_platform__
 WCHAR* pWtemp = new WCHAR[pLen];
 int iWcharLenth = ::MultiByteToWideChar(CP_GB2312, MB_PRECOMPOSED,
                                      pText, -1, pWtemp, pLen);
 if (0 == iWcharLenth)
 {
  DWORD dwLastErr = GetLastError();
     printf("alexaroma:转码错误,错误号:%d/n", dwLastErr);
  delete pWtemp;  return 0;
 }
 int iMultByteLenth = ::WideCharToMultiByte(CP_UTF8, 0, pWtemp,
                                         iWcharLenth, pOut,
              iBufSize, NULL, NULL);
 if (0 == iMultByteLenth)
 {
  DWORD dwLastErr = GetLastError();
  printf("alexaroma:转码错误,错误号:%d/n", dwLastErr);
  delete pWtemp;
  return 0;
 }
 delete pWtemp;
 return iMultByteLenth;
#else//__cdn_win32_platform__
 iconv_t cd;
 int   rc;
 char   **pin   =   &pText;
 char   **pout   =   &pOut;
 int outlen = iBufSize;
 cd=iconv_open("UTF-8","GB2312");
 if(cd==0)return -1;
 memset(pOut,0,strlen(pOut));
 if(iconv(cd,pin,(size_t   *)&pLen,pout,(size_t   *)&outlen) == -1)
 {
  iconv_close(cd);
  return outlen;
 }
 iconv_close(cd);
 return -1;
#endif//__cdn_win32_platform__
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python 3.7.0 重大功能改进 那么,这次新发布的Python 3.7.0 有哪些重要的改进呢?总的来说, 新的syntax功能: PEP 563,推迟了类型注释(type annotations)的评估 向后不兼容的syntax更改: async 和 await 现在是保留关键词 新的库模块: contextvars:PEP 567 - 上下文变量 dataclasse:PEP 557 - 数据类 importlib.resources 新的内置功能: PEP 553,新的 breakpoint() 函数 Python 数据模型改进: PEP 562,定制访问模块属性 PEP 560,核心支持 typing module 和 generic types dict 对象的插入顺序保存性质被纳入Python官方语言规范 标准库的重大改进: asyncio 模块增加了新功能,提高了可用性和性能 time 模块新增纳秒级函数支持,新函数将纳秒数作为整数值返回 CPython 部署改进: 避免使用 ASCII 作为默认文本编码 PEP 552,deterministic .pycs 新的 runtime 模式 PEP 565,改进了 DeprecationWarning 处理 C API 改进: PEP 539,用于线程本地存储的新C API 文档改进: PEP 545,Python文档翻译 新增日语、法语和韩语文档 Python 3.7.0 新增特性 那么,接下来详细看看这些功能。 PEP 563:推迟对注释语句的评估 Python的类型提示有两个明显的可用性问题: 注释只能使用当前范围内已有的名称,换句话说,它们不支持任何类型的前向引用; 注释源代码对Python程序的启动时有不利影响。 通过推迟注释评估可以解决这两个问题。编译器不是编译在定义时在注释中执行表达式的代码,而是将注释以字符串形式存储。如果需要,可以使用typing.get_type_hints()在运行时解析注释。在不需要解析的常见情况下,注释的存储成本更低,并且启动时更快。 PEP 538:C语言环境强制 Python 3系列中的一个持续的挑战是确定一种合理的默认策略,用于处理目前在非Windows平台上使用默认C或POSIX语言环境的“7-bit ASCII”文本编码假设。 PEP 538更新默认解释器命令行界面,自动将该语言环境强制转换为可用的基于UTF-8的语言环境。 自动设置LC_CTYPE意味着核心解释器和C扩展(例如readline)将假设使用UTF-8作为默认文本编码,而不是ASCII。 PEP 540:强制UTF-8 Runtime 模式 新的-X utf8命令行选项和PYTHONUTF8环境变量可用于启用CPython UTF-8模式。 PEP 553:内置breakpoint() Python 3.7新增了内置函数breakpoint(),作为进入Python调试器的简单而一致的方式。 PEP 539:新增用于线程本地存储的C API 虽然Python为线程本地存储支持提供了一个C API; 但现有的线程本地存储(TLS)API使用int来表示所有平台上的TLS密钥,但这既不符合POSIX标准,也不具备任何实际意义上的便携性。 PEP 539通过向CPython提供新的线程本地存储(TSS)API来改变这一点,该API取代了在CPython解释器中使用现有TLS API,同时弃用现有API。TSS API使用新类型Py_tss_t而不是int来表示TSS密钥,这将允许在本地TLS密钥定义的平台上构建CPython。 PEP 562:定制对模块属性的访问 Python 3.7支持在模块上定义__getattr __(),并且只要没有找到模块属性就会调用它。也允许在模块上定义__dir __()。 PEP 564:time 内置函数支持纳秒 为了避免精度损失,PEP 564在timemodule添加了六个新“纳秒”(nanosecond)变量: time.clock_gettime_ns() time.clock_settime_ns() time.monotonic_ns() time.perf_counter_ns() time.process_time_ns() time.time_ns() PEP 565:在__main__中默认显示DeprecationWarning DeprecationWarning的默认处理已更改,以便默认情况下再次显示这些警告,但仅当触发它们的代码直接在__main__模块中运行时才会显示。 PEP 560:新增支持类型模块和泛型 PEP引入了两种特殊方法__class_getitem __()和__mro_entries__,这些方法现在被大多数类和特殊构造用于输入。结果,不同类型的各种操作的速度提高了7倍,可以使用泛型而没有元类冲突,并且修改了类型模块中长期存在的一些bug。 PEP 552:基于哈希的.pyc文件 PEP 552扩展了pyc格式,允许源文件的哈希值用于invalidation,而不是源timestamp。这种.pyc文件称为“hash-based”。默认情况下,Python仍然使用基于时戳的invalidation,并且不会在运行时生成基于哈希的.pyc文件。可以使用py_compile或compileall生成基于哈希的.pyc文件。 PEP 545:Python文档翻译 PEP 545描述了创建和维护Python文档翻译的过程。添加了三种语言的翻译: •日本:https://docs.python.org/ja/ •法语:https://docs.python.org/fr/ •韩国:https://docs.python.org/ko/ 开发运行时模式:-X dev 新的-X dev命令行选项或newPYTHONDEVMODE环境变量可用于启用CPython的开发模式。在开发模式下,CPython执行额外的运行时检查,这些检查无法在默认情况下启用。 性能提升及文档下载 根据官方文档表示,新升级的各种优化使 Linux 上的 Python 启动时减少了 10%,而 macOS 上的启动时更是减少了 30%。 由于字节码更改,方法调用现在可以快 20%。 由于PEP 560工作,typing 导入时减少了 7 倍,现在许多 typing 操作也更快。 等等优化,还有更多。
MyQQ is a cross-platform library for communication which uses a TencentQQ-like protocol to communicate with friends on the Internet. It can work well now and maintained by Xiaoxia ([email protected]). If you are interested in MyQQ and have improved it, I suggest you that you send your source code to me then everyone will know your work and thank you! You can get the latest version of this software (including its source code) at http://home.xxsyzx.com 注意:本软件以及源代码仅供学习研究使用。所用协议皆属个人业余的黑匣分析结果。 Developer List: 小虾 ([email protected]) 千月(改进myqq.c界面) ccpaging Windows编译: 需要Mingw32(Devcpp的bin也可以)。 打开控制台,在当前目录下执行 make -C src clean all Linux编译: 在终端里执行 make -C src -flinux.mak clean all MacOSX编译: 在终端里执行 make -C src -fmac.mak clean all 由于最初没有周全考虑,目前版本暂时不兼容64位的机器,望见谅! Update History: Version 3.17 (2009-6-30) 1. 修正发送消息后头像的变化。 2. 修正09SP1接收信息的bug。 3. 修正0x18包中获取好友失败时的内存访问错误。 4. 修正09SP1系统消息协议。 5. 盲目修正09接收消息的bug。 6. 增加qqconn.c,支持代理登录。 Version 3.16 (2009-6-27) 1. 增加NoColor配置项关闭色彩文字。 2. 增加cls/clear/clrscr命令来清屏。 3. 提示消息发送失败,但不具体。 Version 3.15 (2009-6-24) 1. 增加qqclient_detach()。 2. 编写成libqq,供外部程序调用。 Version 3.14 (2009-6-21) 1. 命令行参数方式登录失败后的死循环。 2. 内核使用QQ2009SP1协议。 3. 修正08之前接收消息的bug。 4. 兼容Mac32。 5. utf8.c里添加qqdef.h头文件。 Version 3.13 (2009-3-29) 1. Linux(Ubuntu) version compiled! Version 3.12 (2009-3-22) 1. 用Windows的Sleep代替不推荐的_sleep。 2. 在Mingw32-gcc4.3.3上编译成功。 Version 3.11 (2009-2-8) 1. 输入验证码提示。 2. 修正myqq.c删除好友的bug。 3. 修正添加附言的bug。 Version 3.10 (2009-2-7) 1. 修正09接收消息协议。 2. 全部源代码文件更改为UNIX-UTF8格式。 3. 增加Preference来自定义屏蔽部分协议。 4. 增加添加、删除好友基本协议,支持验证码。 5. 登录后更改状态。 6. 登录机器数据随机填充。 7. 修正myqq.c里无法打印某些消息的bug。 Version 3.08 (2009-1-27) 1. 修正myqq.c里显示好友状态。 2. 修正因缺少pthread_mutex_destroy引起的资源泄漏(可以检测到)。 3. 修正好友数目多时导致分组信息与群信息未能获取的问题。 4. 10分钟刷新群在线成员。 5. 自动建立qqconfig.txt配置文件。 Version 3.03 (2009-1-26) 1. 修正prot_im.c中buf->pos += get_word( buf );在Linux上运行时发生的错误。 2. 编译Linux版本。 3. qqconfig.txt缺失提示。 Version 3.00 (2009-1-25) 1. 更换QQ2008贺岁版协议为QQ2009Preview4协议。 2. 全面使用utf8,myqq.c为Windows用户转换为gb。 3. 移除所有多余,功能不确切的协议处理函数。 4. 能够接收08,09协议的好友消息与群消息。 5. 处理消息中的表情字符,转换成[face:*]以及[image]来表示。 Version 2.95 (2008-10-26) 1. 处理返回NULL的可能。 2. 服务器列表由配置文件导入。 Version 2.9 (2008-10-1) 1. 支持字符颜色显示。 2. 中文字符界面。 3. 补充了几个新的服务器IP。 4. 输入密码时去掉回显或打*。 5. 修正prot_login_verify_password_reply处理返回包的误解,感谢CC-Akita(CCPaging)。 6. 增加Dev-cpp工程文件,增加程序图标。 7. Makefile里定向pthread库,便于不同环境的编译。 Version 2.8 (2008-8-3) 1. Linux Build Support. Version 2.7 (2008-8-2) 1. 使用上次登录IP,加快多Q登录速度。 2. 修正list.c里添加项在满时没有返回<0的漏洞。 3. 在登录未完成时,不接收消息。 Version 2.6 (2008-7-27) 1. 登录中的未知字节用0填充,原来是用随机数。 2. 根据文档,进一步完善登录协议,但还是没有解决验证码的出现问题。 Version 2.5 (2008-7-26) 1. 修正一个发包的bug,包被送进已发送队列之后time_alive应该为当前时。之前因为 这个问题,导致一个包超时其他包也要重发? 2. 恢复注销命令(没有这个,怎么下线呢)。 3. 登录首先获取所有钥匙,避免出现登录后被Kick out。 4. 感谢网友008的提醒,号码格式化字符%d已被替换为%u。 Version 2.4 (2008-7-24) 1. 好友添加。 2. Packed with pthread library. 3. 删除注销命令(可能引发异常) 4. 重发时长为6秒 Version 2.3 (2008-7-22) New features: 1. 支持UDP协议登录。 2. 调整了登录后的发包次序。 3. 好友使用qsort快排。 4. 完善了event的缓冲区,和以前的webqq结合使用。 5. 使用assert函数,便于精简发布版本的代码。 Version 2.0 (2008-7-17) New featrues: 1. 包管理器的链表改用loop数据结构,精简代码,减少错误。 2. (--a)%b可能为负数,原来没注意到,引发了改写mcb的内存错误。 3. 发包序号策略改善,不再每次发包都递增。 Version 1.9 (2008-7-15) New features: 1. 重新策划程序,采用QQ2008贺岁版协议。 2. 原来的group改名为qun,原group被用作管理好友分租。 3. 增加memory.c内存管理和debug.c调试信息及日志记录。 4. ccpaging建议改掉qqqun这个结构名,我打算下个版本把它改为qun_t,其它类似如 member_t, group_t, buddy_t。 5. 具备登录输入验证码功能,验证码图片保存在web/verify目录下。 6. 修正qqsocket里接收数据溢出。 Version 0.9 (2008-2-12) New features: 1. MyQQ库可以登录多个ID,API全部更新。 2. 修正好友名称里混有QQ号码和特殊字符。 3. 完善了好友状态回调。 4. 延长了重发包的时,避免发送两次。 5. 修正在自动回复时控制台提示的问题。 6. 回调函数全部使用stdcall模式。 Version 0.6 (2008-2-5) New features: 1. Wait for message to send. 2. Improve input. 3. Check for repeated messages. 4. Add refresh command. Version 0.5 (2008-2-4) New features: 1. Send message to group. 2. Get group list. 3. List groups, online users and online group members. 4. Get group member information. 5. Get buddy information. 6. The original interface works. Version 0.1 (2008-2-1) Use QQ2006 Protocol to login. Support Receiving messages from buddies and groups, sending messages to buddies. Compiled and linked on Linux(GCC 4.1, Debian etch). Compiled and linked on Windows(MingwGCC 3.4.2).
更新说明: 2017-02-04(yaya) Ls command: Empty Folder returns false. 2016-12-08(yaya) 修正lz4、vhd不显示解压缩进度指示。增加lzma解压缩进度指示。 2016-11-09(不点) 0x8205 bit 5 = 1: 使checkkey闲置循环停止指令。 2016-04-13(yaya) 支持动画菜单 setmenu --graphic-entry=类型=菜单行数=菜单列数=图形宽(像素)=图形高(像素)=菜单行距(像素) 菜单项0的路径文件名 类型: 位0:高亮指定颜色 位1:高亮颜色翻转 位2:高亮显示线框 位7:背景透明(最好使用黑色背景) 文件名: *n.??? 格式 n=00-99 高亮颜色由 color HIGHLIGHT=0xrrggbb 指定。 字符可以使用任意字型、字高、颜色,可以辅以图标。 2016-03-25(yaya) 菜单字符可以使用不同字型。 例如:"七" 使用不同字型,将 .hex 文件中的 unicode 码 “4e03” 修改为 “0080”, 将菜单中的 "七" 修改为 “\X0080”。 2016-03-23(yaya) 增强 echo 函数功能。 例如:echo -e \x18 显示 UTF-8 字符 0x18。 echo -e \X2191 显示 unicode 字符 0x2191。 2016-03-15(yaya) 1.增加动画控制热键 F2:播放/停止。 2.增加动画控制位 0x835b,位0:0/1=停止/播放。 3.增加精简字库模式:--simp=起始0,终止0,...,起始3,终止3 中文可以使用 --simp= ,内置字库应当包含 DotSize=[font_h],['simp'] 例如:font --font-high=24 --simp= /24_24.hex DotSize=24,simp 不使用热键: 可以加载 32*32 unifont 全字库 使用热键: 可以加载 24*24 unifont 全字库 使用精简字库: 可以加载 46*46 汉字全字库 使用精简字库及热键:可以加载 40*40 汉字全字库 4.不再支持 bin 格式字库。 2016-03-03(yaya) 1.增加图像背景色设置方法。 splashimage --fill-color=[0xrrggbb] 作用之一,作为小图像的背景。 作用之二,直接作为菜单的背景(即不加载图像背景)。此时只设置字体的前景色即可。 2.增加动画菜单。 splashimage --animated=[type]=[delay]=[last_num]=[x]=[y] START_FILE 类型[type]:bit 0-3: 播放次数 bit 4: 永远重复 bit 7: 透明背景 type=00:禁止播放 播放n次:序列图像各显示n次,时独占。可作为启动前导、序幕。 永远重复:序列图像无限循环,时与菜单共享。可作为菜单里的动画。 背景透明:即抠像。要求4角像素为背景色。 背景色最好为白色或黑色,这样可以去除一些灰色杂波。若是彩色背景,则应当非常干净。 提醒:请以16进制方式输入。否则易错。 延迟[delay]:序列图像之的延迟。单位是滴答,即1/18.2秒。 序列数[last_num]:序列图像总数(2位数,从1开始计数)。 偏移[x]、[y]:图像偏移,单位像素。 起始图像文件 START_FILE 命名规则:*n.??? n: 1-9 或 01-99 或 001-999。 3.增加固定图像的背景色可以透明。 splashimage [--offset=[type]=[x]=[y]] FILE 类型[type]:bit 7: 透明背景 2016-02-14(yaya) setmenu 函数增加菜单项目背景短/满参数(默认短) 2016-01-19(yaya) splashimage 函数增加图像起始偏移(默认0) 2015-08-20(yaya) 1.支持非

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值