作者smartboy (小光光)
看板Liu
标题liu-uni*.tab 的格式
时间Fri Nov 24 22:30:43 2006
虽然 liu-uni*.tab 的格式早已不是什麽秘密, 许多程式都能直接读写,
也有像 boshcvterv21 [1] 的工具程式. 但公开的文件似乎只有 liubig5.tab 的说明
(也许只是我找不到)
由於我在 FreeBSD 也需要类似 boshcvterv21 的工具, 所以我观察了一下
liu-uni*.tab 的格式, 简单说明如下, 让有兴趣的朋友也能自己写程式处理.
我只简要介绍, 请参照 liubig5.tab 的格式说明会比较清楚.
表格大致可分五部份, 依序是
1. 32*32 的 index, 每个 2byte, 基本上跟 big5 版一样,
0~31 表示 " abcdefghijklmnopqrstuvwxyz,.'[]"
差别在於 big5 版记的是档案中的位址, unicode 版记的是字的个数
(因为档案超过 64k 了)
接着有 2byte, 其值表示总共有 n 个字
2. 接下来 2n 个 bit, 每字 2bit, 表示每个字的最高位 2bit
最後不足 1byte 的部份补零
3. 接下来 n 个 bit, 每字 1bit, 我还不清楚用途为何
这就是 boshcvterv21 输出的 + 号,
还望板上各位解说
最後不足 1byte 的部份补零
4. 接下来 n 个 bit, 每字 1bit, 表示是否最简码, 0b=最简码, 1b=非最简码
这就是 boshcvterv21 输出的 * 号
最後不足 1byte 的部份补零
5. 接下来 3n 个 byte, 每字 3byte, 跟 big5 版的格式相同,
前 10bit 分别表示第 3,4 按键, 之後的 14bit 是该字的低位元
这 14bit 与第 2 部份的 2bit 组成一个完整的字, 采用 unicode 值.
由於不会有空白开头的拆法, 所以 .tab 的前 64byte 其实可以挪作其他用途.
观察发现
0~1 byte 刚好是第 2 部分开始的位址,
2~3 byte 刚好是 2n bit 所需的 byte 数, 也就是第 2 部分的长度
4~5 byte 刚好是字数, 也就是 n
6~7 byte 刚好是 n bit 所需的 byte 数, 也就是第 3,4 部分的长度
其他看起来都是 0
[1]
http://liu.twbbs.org/liuftp/tools/
由於还不至於太长, 以下附上我写的 perl 程式, 可将 liu-uni*.tab 转成文字档
文字档转 tab 则留给有兴趣的人当习题 ;)
#!/usr/bin/perl
use encoding 'utf8';
use integer;
my $filename = shift || 'liu-uni.tab';
open F, '<:raw', $filename or die $!;
{
use bytes;
local $/;
@b = map ord, split //,<F>;
}
close F;
$i1 = getint16(0);
$words = getint16(4);
$i2 = $i1 + getint16(2); # or + ($words*2+7)/8
$i3 = $i2 + getint16(6); # or + ($words*1+7)/8
$i4 = $i3 + getint16(6); # or + ($words*1+7)/8
#printf "words %d 0x%x\n", $words, $words;
#printf "i1=0x%x, i2=0x%x, i3=0x%x, i4=0x%x\n", $i1, $i2, $i3, $i4;
my @rootkey = (split //," abcdefghijklmnopqrstuvwxyz,.'[]");
for my$i(0 .. 1023) {
my @key;
$key[0] = $rootkey[$i/32];
$key[1] = $rootkey[$i%32];
next if $key[0] eq ' ';
for $ci(getint16($i*2) .. getint16($i*2+2)-1) {
my $bit24 = getbits($i4, 24, $ci);
my $hi = getbits($i1, 2, $ci);
my $lo = $bit24 & 0x3fff;
#printf "%x %04x\t", $hi, $lo;
$key[2] = $rootkey[$bit24>>19];
$key[3] = $rootkey[$bit24>>14 & 0x1f];
my $flag_unknown = getbits($i2, 1, $ci);
my $flag_sp = getbits($i3, 1, $ci);
print join '', @key;
$char = chr($hi<<14 | $lo);
printf "\t%s", $char;
printf "\t%s", $flag_sp?' ':'*';
printf "%s", $flag_unknown?' ':'+';
print "\n";
}
}
sub getint16 {
my($addr)=@_;
return $b[$addr] | $b[$addr+1]<<8;
}
sub getbits {
my($start, $nbit, $i) = @_;
if($nbit==1 || $nbit==2 || $nbit==4) {
my($byte)=$b[$start+$i*$nbit /8];
my $ovalue = $byte>>(8-$nbit - $i*$nbit %8);
return $ovalue & ((1<<$nbit)-1);
} elsif($nbit>0 && $nbit%8==0) {
my $nbyte = $nbit / 8;
my $value = 0;
my $a = $start + $i * $nbyte;
while($nbyte--) {
$value = $value<<8 | $b[$a++];
}
return $value;
} else {
die;
}
}
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 203.204.141.15
1F:推 Fenikso:liu-uni1.tab後面还有同音字对照表和一段垃圾 11/25 03:28
2F:→ Fenikso:不过那好像有没有都没差.. 11/25 03:28