精華區beta Liu 關於我們 聯絡資訊
雖然 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