作者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
推 Fenikso:liu-uni1.tab後面還有同音字對照表和一段垃圾 11/25 03:28
→ Fenikso:不過那好像有沒有都沒差.. 11/25 03:28