问题来源:
http://www.cnblogs.com/del/archive/2008/11/22/1284923.html#1378410
Delphi 2009 默认的编码是多字节编码(MBCS), Delphi 这样表示它: TEncoding.Default.
下面是多字节编码与汉字之间转换的例子:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{汉字到多字节编码}
procedure TForm1.Button1Click(Sender: TObject);
var
stream: TStringStream;
b: Byte;
s: string;
begin
stream := TStringStream.Create('我们', TEncoding.Default);
s := '';
for b in stream.Bytes do s := Format('%s%x ', [s,b]);
ShowMessage(s); {CE D2 C3 C7}
stream.Free;
end;
{多字节编码到汉字}
procedure TForm1.Button2Click(Sender: TObject);
var
stream: TStringStream;
begin
stream := TStringStream.Create;
stream.Size := 4;
stream.Bytes[0] := $CE;
stream.Bytes[1] := $D2;
stream.Bytes[2] := $C3;
stream.Bytes[3] := $C7;
ShowMessage(stream.DataString); {我们}
stream.Free;
end;
{把多字节编码的字符串转换到汉字}
procedure TForm1.Button3Click(Sender: TObject);
var
str: AnsiString;
stream: TStringStream;
i: Integer;
begin
str := 'CED2C3C7';
stream := TStringStream.Create;
stream.Size := Length(str) div 2;
for i := 1 to Length(str) do
if Odd(i) then
stream.Bytes[i div 2] := StrToIntDef(Concat(#36,str[i],str[i+1]), 0);
ShowMessage(stream.DataString); {我们}
stream.Free;
end;
end.
posted @
2008-11-23 12:31 万一 阅读(38) |
评论 (6) |
编辑
{函数}
function SetScreen(x,y: Word): Boolean;
var
DevMode: TDeviceMode;
begin
Result := EnumDisplaySettings(nil, 0, DevMode);
if Result then
begin
DevMode.dmFields := DM_PELSWIDTH or DM_PELSHEIGHT;
DevMode.dmPelsWidth := x;
DevMode.dmPelsHeight := y;
Result := ChangeDisplaySettings(DevMode, 0) = DISP_CHANGE_SUCCESSFUL;
end;
end;
{测试}
procedure TForm1.Button1Click(Sender: TObject);
begin
SetScreen(1024, 768);
end;
posted @
2008-11-19 17:14 万一 阅读(169) |
评论 (22) |
编辑
下面是常用编码的识别符, 在 Delphi(2009) 中如何获取呢?
Unicode:
FF FE; BigEndianUnicode:
FE FF; UTF8:
EF BB BF
var
bs: TBytes;
b: Byte;
str: string;
begin
{只有 Unicode、BigEndianUnicode、UTF8 编码有识别符}
bs := TEncoding.Unicode.GetPreamble;
str := '';
for b in bs do str := Format('%s %x', [str, b]);
ShowMessage(str); {FF FE}
bs := TEncoding.BigEndianUnicode.GetPreamble;
str := '';
for b in bs do str := Format('%s %x', [str, b]);
ShowMessage(str); {FE FF}
bs := TEncoding.UTF8.GetPreamble;
str := '';
for b in bs do str := Format('%s %x', [str, b]);
ShowMessage(str); {EF BB BF}
{ASCII、UTF7 和 Default(默认编码) 没有识别符}
bs := TEncoding.ASCII.GetPreamble;
str := '';
for b in bs do str := Format('%s %x', [str, b]);
ShowMessage(str); {无}
bs := TEncoding.UTF7.GetPreamble;
str := '';
for b in bs do str := Format('%s %x', [str, b]);
ShowMessage(str); {无}
bs := TEncoding.Default.GetPreamble;
str := '';
for b in bs do str := Format('%s %x', [str, b]);
ShowMessage(str); {无}
end;
posted @
2008-11-19 16:42 万一 阅读(205) |
评论 (0) |
编辑
在没有 Uncode 的时代, 用 256 个 ACSII 只是方便了英文, 其他文字怎么办?
那时是各自为政的, 譬如中文就有: GB2312-80(国内简体)、Big5(台湾繁体)、HKSCS(香港繁体), 但它们互不兼容.
GB2312(1980年) 后来升级到 GBK(1995年), 现在电脑上使用的是 GB18030(2000年), 这个系列是向后兼容的.
区位码的概念是在 GB2312 时提出的, GB2312 是一个 94*94 的二维表, 行就是 "区"、列就是 "位", 譬如 "万" 字在 45 区 82 位, 所以 "万" 字的区位码是: 4582.
00-09 区(682个): 是符号、数字、英文字符...制表符等;
10-15 区: 空白, 留待扩展;
16-55 区(3755个): 常用汉字(也有叫一级汉字), 按拼音排序;
56-87 区(3008个): 非常用汉字(也有叫二级汉字), 这是按部首排序的;
88-94 区: 空白, 留待扩展.
还有两个概念: 国际码、内码.
先转一下话题: 打开记事本输入 "万" 字, 保存(编码选择 ANSI); 然后用二进制编辑器(譬如: UltraEdit) 打开, 会看到:
CD F2, 这就是 "万" 字的内码!
那什么又是国际码呢?
咱们的 GB2312 用一个二维表表示了咱们需要的字符, 其他文字可能也是如此; 为了区别, 所以有国际组织规定把咱们的 "区" 和 "位" 分别加上 32(十六进制表示: $20; 二进制表示: 00100000) 作为国际码(那其他文字应该加另外一个不同的数字).
这样我们可以算出(45+32, 82+32):
"万" 字的国际码是 77 114($4D72)
不过这还不能在计算机上使用, 因为这样会和早已通用的 ASCII 码混淆(导致乱码), 譬如: 77 是 ASCII 的 "M", 114 是 ASCII 的 "r".
所以又有规定把每个字节的最高位都从 0 换成 1(这之前它们都是 0), 或者说把每个字节(区和位)都再加上 128(十六进制的: $80; 二进制的: 10000000), 从而得到 "机内码", 也就是前面所说的 "内码".
总结一下: 从区位码, 区和位分别 +32 得到国际码, 再分别 +128 得到内码;
简化一下: 区位码的区和位分别 +160 即可得到内码, 用十六进制表示: 区位码 + $A0A0 = 内码.
验证一下前面从记事本输入得到的 CD F2:
45 + 160 = 205; (205 就是 十六进制的 $CD)
82 + 160 = 242; (242 就是 十六进制的 $F2)
这样, 内码的两个字节的最高位就都是 1 了, 另外 ASCII 的(0-254)最高位都是 0, 所以有人也使用这个特点来区别汉字.
虽然 Window 2000 开始, 系统已经使用 Uncode 编码了, 其实咱们现在还是使用的这种双字节内码, 这是系统根据我们选择的字符集自动转换的.
此时再看前面的函数
http://www.cnblogs.com/del/archive/2008/11/19/1336444.html 应该不会有困难了.
posted @
2008-11-19 10:41 万一 阅读(130) |
评论 (0) |
编辑
先上转换函数:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{查汉字区位码}
function Str2GB(const s: AnsiString): string;
const
G = 160;
begin
Result := Format('%d%d', [Ord(s[1])-G, Ord(s[2])-G]);
end;
{通过区位码查汉字}
function GB2Str(const n: Word): string;
const
G = 160;
begin
Result := string(AnsiChar(n div 100 + G) + AnsiChar(n mod 100 + G));
end;
{测试}
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(GB2Str(4582)); {万}
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage(Str2GB('万')); {4582}
end;
end.
获取区位码表: 准备个 Memo 接收(注意使用了上面的函数)
var
i,j: Byte;
s: string;
begin
s := '';
for i := 1 to 94 do
begin
for j := 1 to 94 do
s := Format('%s %s', [s, GB2Str(i*100 + j)]);
Memo1.Lines.Add(s);
s := '';
end;
end;
posted @
2008-11-19 10:14 万一 阅读(146) |
评论 (0) |
编辑