Delphi与字符编码(实战篇)(MultiByteToWideChar会返回转换后的宽字符串长度)
本文目标:
- 了解Delphi的字符串类型
- 字符编码的检测与转换
- 简体繁体转换
0. 导言
看完“.Net与字符编码(理论篇)”,我们明白了字符是自然语言中的最小单位,在存储和传输的过程中可以使用三种编码方法:ASCII、DBCS以及Unicode。常见的DBCS编码有GB2312、GBK和BIG5,而UTF-8、UTF-16和UTF-32则是最常用的Unicode编码类型。
1. 字符串类型
在Delphi中有两种字符串类型:AnsiString和WideString。AnsiString被称为“长字符串”(Long String);WideString则叫做“宽字符串”(Unicode String),它和COM String (BSTR)兼容。它们都是由程序在堆(Heap)上分配的并自动管理内存的分配和释放。目前在Win32平台上,string类型等同于AnsiString。AnsiString还可以理解成字节序列,它支持单字节字符编码(SBCS)、多字节字符编码(MBCS/DBCS)以及UTF-8编码。而WideString使用UTF-16编码,完美支持Unicode。
为了说明字符和字节的区别,我们来看一个计算字符个数的例子:
procedure TestAnsiLength;
var
str: string;
begin
str := '汉字ABC';
Assert(Length(str) = 7); // 7个字节
Assert(AnsiLength(str) = 5); // 5个字符
end;
下面是AnsiLength的两种实现:
function AnsiLength(const s: string): integer;
var
p, q: PChar;
begin
Result := 0;
p := PChar(s);
q := p + Length(s);
while p < q do
begin
Inc(Result);
if p^ in LeadBytes then // 当前系统代码页的前导字节数组
Inc(p, 2)
else
Inc(p);
end;
end;
function AnsiLength(const s: string): Integer;
begin
Result := MultiByteToWideChar(CP_ACP, 0, PAnsiChar(s), -1, nil, 0);
if Result > 0 then Dec(Result); // 除去终止符
end;
如果理解了.Net与字符编码(理论篇)中的编码知识,上面的例子还是很简单的。
2. 字符编码的检测与转换
“工欲善其事,必先利其器”,我先向大家推荐一些工具:
- JCL (JEDI Code Library)
- Virtual TreeView
- Tnt Controls or TMS Unicode Component Pack
定义基本的类型:
TEncodingType = (
etAnsi, // ANSI format (SBCS/DBCS)
etUTF8, // UTF-8 format
etUnicode, // UTF-16 format using little endian
etUnicodeBE, // UTF-16 format using big endian
etUTF32, // UTF-32 format using little endian
etUTF32BE // UTF-32 format using big endian
);
{ 字节顺序标记 }
TByteOrderMask = array of Byte;
获得不同编码类型的BOM:
function TryGetBOM(const encodingType: TEncodingType; var bom: TByteOrderMask): Boolean;
begin
Result := True;
case encodingType of
etUTF8: CopyBytes(BOM_Utf8, bom);
etUnicode: CopyBytes(BOM_UTF16_LSB, bom);
etUnicodeBE: CopyBytes(BOM_UTF16_MSB, bom);
etUTF32: CopyBytes(BOM_UTF32_LSB, bom);
etUTF32BE: CopyBytes(BOM_UTF32_MSB, bom);
else
begin
SetLength(bom, 0);
Result := False;
end;
end;
end;
检测字符编码类型:
begin
if CompareBOM(buffer, BOM_UTF8) then
Result := etUTF8
else if CompareBOM(buffer, BOM_UTF16_LSB) then
Result := etUnicode
else if CompareBOM(buffer, BOM_UTF16_MSB) then
Result := etUnicodeBE
else if CompareBOM(buffer, BOM_UTF32_LSB) then
Result := etUTF32
else if CompareBOM(buffer, BOM_UTF32_MSB) then
Result := etUTF32BE
else
Result := etAnsi;
end;
function DetectEncoding(stream: TStream): TEncodingType; overload;
var
pos: Int64;
bytes: TByteOrderMask;
begin
SetLength(bytes, 6);
ZeroMemory(@bytes[0], Length(bytes));
pos := stream.Seek(0, soFromCurrent);
stream.Seek(0, soFromBeginning);
stream.Read(bytes[0], SizeOf(bytes));
stream.Seek(pos, soFromBeginning);
Result := DetectEncoding(PAnsiChar(@bytes[0]));
end;
下面的方法演示了如何用不同的编码类型来保存文本:
const encodingType: TEncodingType; withBom: Boolean = False);
var
s: AnsiString;
p: PAnsiChar;
bom: TByteOrderMask;
bytes: Integer;
begin
p := nil;
bytes := Length(buffer) * SizeOf(WideChar);
if withBom and TryGetBOM(encodingType, bom) then
begin
stream.Write(bom[0], Length(bom));
end;
case encodingType of
etAnsi:
begin
p := PAnsiChar(buffer);
bytes := Length(buffer);
end;
etUTF8:
begin
s := Utf8Encode(buffer);
p := PAnsiChar(s);
bytes := Length(s);
end;
etUnicode:
begin
p := PAnsiChar(PWideChar(buffer));
end;
etUnicodeBE:
begin
StrSwapByteOrder(PWideChar(buffer));
p := PAnsiChar(PWideChar(buffer));
end;
else // 留给读者去实现
begin
raise Exception.Create('Not Implemented.');
end;
end;
stream.Write(p^, bytes);
end;
需要说明的是,如果把这些过程封装成对象的话,结构会更清晰。
3. 简体繁体转换
简体繁体转换包括简转繁和繁转简两种情况,其原理是利用查找字符编码映射表来查找相应的字符。网上有一个“利用编码对照表完成内码转换和简繁体转换的单元”就是基于这个原理写的,在这里就暂不详述了。
{ TODO: 采用OOP来封装字符编码模块,并提供下载 }
{ TODO: 研究简体繁体转换 }
参考文章
http://www.cnblogs.com/baoquan/articles/1027371.html
Delphi与字符编码(实战篇)(MultiByteToWideChar会返回转换后的宽字符串长度)的更多相关文章
- 字符编码和python使用encode,decode转换utf-8, gbk, gb2312
ASCII码 标准ASCII码使用7位二进制数表示大写或小写字母,数字0到9标点符号以及在美式英语中使用的特殊控制字符. 在标准ASCII码中,最高位(b7)用作奇偶校验位,所谓奇偶校验,是指在代码传 ...
- 关于Unicode,字符集,字符编码,每个程序员都应该知道的事
关于Unicode,字符集,字符编码,每个程序员都应该知道的事 作者:Jack47 李笑来的文章如何判断一个人是否聪明?中提到: 必要.清晰.且准确的概念,是一切思考的基石.所谓思考,很大程度上,就是 ...
- 关于Unicode,字符集,字符编码
基本概念 字符[character] 字符代表了字母表中的字符,标点符号和其他的一些符号.在计算机中,文本是由字符组成的. 字符集合[character set] 由一套用于特定用途的字符组成,例如支 ...
- 字符编码之间的相互转换 UTF8与GBK(转载)
转载自http://www.cnblogs.com/azraelly/archive/2012/06/21/2558360.html UTF8与GBK字符编码之间的相互转换 C++ UTF8编码转换 ...
- 【miscellaneous】【C/C++语言】UTF8与GBK字符编码之间的相互转换
UTF8与GBK字符编码之间的相互转换 C++ UTF8编码转换 CChineseCode 一 预备知识 1,字符:字符是抽象的最小文本单位.它没有固定的形状(可能是一个字形),而且没有值." ...
- python标准库之字符编码详解
codesc官方地址:https://docs.python.org/2/library/codecs.html 相关帮助:http://www.cnblogs.com/huxi/archive/20 ...
- JAVA的字符编码及问题
web开发时,字符编码及有时候也会是一个麻烦的问题,没有经验的话,肯定不知道怎么解决,有一定的经验的话,那还是比较简单的.以下,是我学习过程中总结出来的几种字符编码级问题和其解决的方法 1.文档乱码, ...
- 001. Java内存中的字符编码
Java内存中的字符编码 Unicode字符集及utf-8 .utf-16.utf-32 等字符编码方式 字符集:字符表示的数字集合,元素称为码点或码位: 字符编码:字符实际的储存表示: 码点:一个码 ...
- 字符编码(续)---Unicode与ANSI字符串转换以及分辨字符编码形式
Unicode与ANSI字符串转换 我们使用windows函数MultiByteToWideChar将多字节字符串转换为宽字符字符串,如下: int MultiByteToWideChar( UINT ...
随机推荐
- Node.js how to respond to an upgrade request?
You just need to call socket.write with the appropriate HTTP syntax as plain text along these lines ...
- hdu 1428 漫步校园
http://acm.hdu.edu.cn/showproblem.php?pid=1428 dijstra+dp; #include <cstdio> #include <queu ...
- 开源C/C++网络库比较
在开源的C/C++网络库中, 常用的就那么几个, 在业界知名度最高的, 应该是ACE了, 不过是个重量级的大家伙, 轻量级的有libevent, libev, 还有 Boost的ASIO. ACE是一 ...
- HttpApplication实战大文件上传 (第四篇)
一.Asp.net中的文件上传 在Asp.net 1.1中,文件在上传过程中将被全部保存在内存中,对于大文件来说,会造成内存空间的过度使用,可能会招致恶意攻击.为了解决这个问题,Asp.net在配置文 ...
- 2015第10周四-CSS小结
这两天做前台页面发现个人在CSS前端方法很多基础知识都忘了,晚上又搜索学习了下,把相关内容摘录总结. CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明. selector {declara ...
- 8个华丽的HTML5相册动画欣赏
HTML5的图片动画非常丰富,我们也在网站上分享过很多关于HTML5的图片动画.相册在网络中也十分常见,本文我们要分享一些比较华丽的jQuery/HTML5相册动画,希望大家喜欢. 1.HTML5 3 ...
- Generate Parentheses 解答
Question Given n pairs of parentheses, write a function to generate all combinations of well-formed ...
- LeeCode-Two Sum
Given an array of integers, find two numbers such that they add up to a specific target number. The ...
- Zookeeper 5、Zookeeper应用场景
应用场景1 .统一命名服务 » 分布式应用中,通常需要有一套完整的命名规则,既能够产生唯一的名称又便于人识别和记住,通常情况 下用树形的名称结构是一个理想的选择,树形的名称结构是一个有层次的目录结构, ...
- java多线程 并发 编程
转自:http://www.cnblogs.com/luxiaoxun/p/3870265.html 一.多线程的优缺点 多线程的优点: 1)资源利用率更好 2)程序设计在某些情况下更简单 3)程序响 ...