汉字区位码

unit uGBK;

{
  汉字与区位码

  分析

  在没有 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 编码了, 其实咱们现在还是使用的
  这种双字节内码, 这是系统根据我们选择的字符集自动转换的. 
}

interface

uses
  Classes,Sysutils;

  function Str2GB(const s: AnsiString): string;
  function GB2Str(const n: Word): string;

implementation

{查汉字区位码}
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;

end.

你可能感兴趣的:(汉字区位码)