• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Delphi与字符编码(实战篇)

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
本文目标:
  • 了解Delphi的字符串类型
  • 字符编码的检测与转换
  • 简体繁体转换

0. 导言

看完“类型。

1. 字符串类型

在Delphi中有两种字符串类型:AnsiStringWideString。AnsiString被称为“长字符串”(Long String);WideString则叫做“宽字符串”(Unicode String),它和COM String (BSTR)兼容。它们都是由程序在(Heap)上分配的并自动管理内存的分配和释放。目前在Win32平台上,string类型等同于AnsiString。AnsiString还可以理解成字节序列,它支持单字节字符编码(SBCS)、多字节字符编码(MBCS/DBCS)以及UTF-8编码。而WideString使用UTF-16编码,完美支持Unicode。

为了说明字符和字节的区别,我们来看一个计算字符个数的例子:
// 假设当前系统页为CP936(GBK 1.0)
procedure TestAnsiLength;
var
  str: 
string;
begin
  str :
= '汉字ABC';
  Assert(Length(str) 
= 7);      // 7个字节
  Assert(AnsiLength(str) = 5);  // 5个字符
end;

下面是AnsiLength的两种实现:
// uses SysUtils;
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;

// uses Windows;
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. 字符编码的检测与转换

“工欲善其事,必先利其器”,我先向大家推荐一些工具:
定义基本的类型:


获得不同编码类型的BOM:

end;


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;

检测字符编码类型:

function DetectEncoding(buffer: PAnsiChar): TEncodingType; overload;
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;

下面的方法演示了如何用不同的编码类型来保存文本:
procedure WriteText(stream: TStream; const buffer: WideString;
  
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: 研究简体繁体转换 }

参考文章




鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
BSP文件读取(Delphi实现)发布时间:2022-07-18
下一篇:
delphi中我用定时器每隔一段时间执行操作发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap