ByteMap的應用
這個東西的用途廣範,其中一個例子就是基於對照表來編譯出對照表的程序源碼。

轉換器示範

需求:php, g++ compiler

示範核心文件:
mkcstable.php (cj)
mkcstable.php (s2trad)

1. 編譯倉頡轉換器

# 利用 mkcstable 編譯對照表程式碼
~/wconv $ cd codegen/cj/
~/wconv/codegen/cj $ php mkcstable.php
Table file: cj.cin
Catergorizing bytes...
Generating byte functions...
  ascii, Analyzing levels ... done

# 編譯主程序
~/wconv/codegen/cj $ cd ../../native/cj/
~/wconv/native/cj $ g++ *.cpp -O3 -o cj

2. 編譯 簡->繁 轉換器

# 同樣地,利用 mkcstable 編譯對照表程式碼
~/wconv $ cd codegen/s2trad/
~/wconv/codegen/s2trad $ php mkcstable.php 
Table file: phrase_s2t.txt
Catergorizing bytes...
Generating byte functions...
  byte6, Analyzing levels ...
  byte5, Analyzing levels ...
  byte4, Analyzing levels ...
  byte3, Analyzing levels ...
  byte2, Analyzing levels ...
  ascii, Analyzing levels ... done
Table file: word_s2t.txt
Catergorizing bytes...
Generating byte functions...
  byte6, Analyzing levels ...
  byte5, Analyzing levels ...
  byte4, Analyzing levels ...
  byte3, Analyzing levels ...
  byte2, Analyzing levels ...
  ascii, Analyzing levels ... done

# 編譯主程序
~/wconv/codegen/s2trad $ cd ../../native/s2trad/
~/wconv/native/s2trad $ g++ *.cpp -O3 -o s2trad

核心文件說明

說明一下 mkcstable 是如何應用 ByteMap 編譯出C++的源碼。

1. mkcstable.php (cj)

首先得解釋倉頡輸入對照表的模式,截取「日」以開頭的首六個輸入序列:
a 日
a 曰
aa 昌
aa 昍
aaa 晶
aamh 暘
其中「a」為 日,所以:
日      -> 日
日      -> 曰
日日    -> 昌
日日    -> 昍
日日日   -> 晶
日日一竹 -> 暘

function get_function_group::foreach

由於單一個「日」有兩個可能(日\曰),所以轉換時需要指定結果。不指定就預設為第一個。
所以以下輸入會有這樣的輪出:
a -> 日
a1 -> 日
a2 -> 曰
以上寫成代碼:
if ( str[0] == 'a' )
{  
    if ( str[1] == '2' && str[2] == 0 )
    { 
        return "曰";
    }
    else if ( str[1] == '1' && str[2] == 0 )
    { 
        return "日";
    }
    else if( str[1] == 0 )
    { 
        return "日";
    }
}
所以在ByteMap處理之前必先將對照表改為:
a 日
a1 日
a2 曰
aa 昌
aa1 昌
aa2 昍
aaa 晶
aamh 暘

dvorak

由於對照表的輸入預設為標準鍵盤,使用 dvorak 的我自然不能接受,所以這個 function 就是將標準鍵的佈局改為 dvorak 鍵。
所以如果各位是用標準鍵的話,在執行 mkcstable 之前請先將以下這一行 comment-out:
 // to dvorak                                                                     
$v1 = dvorak($v1);

2. mkcstable.php (s2trad)

一篇文章對電腦來說就是一堆 0011 ,而四個 1 等於一個 F ,兩個 F 就是一個 byte,ASCII 就在一個 byte ( x < 0XFF ) 的範圍內。UTF8 的長度可變,所以一篇文章就會像這個樣子:
e5 8f b0 e7 89 88 20 e8 bd ac e8 87 aa 20 e8 b4 ...
所以得逐個 byte 測試該序列是屬於那一個組別:
UTF8 的首個 byte 可以定義該符號的長度,UTF8 的長度分為 6 組:
0x7E byte 6
0x3E byte 5
0x1E byte 4
0x0E byte 3
0x06 byte 2
< 128 ASCII

舉個列,「切」的 UTF8 碼為 0xE58887

取首個 byte:
0xE5 >> 1 == 0x7E ( False )
0xE5 >> 2 == 0x3E ( False )
0xE5 >> 3 == 0x1E ( False )
0xE5 >> 4 == 0x0E ( True )

所以「切」的長度為 3 個 byte:
E5 88 87
其實對轉換器來說,字的長度跟轉換沒什麼關係,不過這會影響轉換的速度,所以每個長度的組別都會分別測試。

為什麼字的長度會影響轉換速度?
這裹用比較的方式,如果我將整個對照表合成一個 function ,那麼
0x7E FF FF FF FF FF

假設巢狀跳轉有以下支點:
0x7E FF
0x7E FF FF
0x7E FF FF FF
0x7E FF FF FF FF
0x7E FF FF FF FF FF

那麼程序必先應過以上五個跳轉,才能得出 0x7E FF FF FF FF FF 這個字沒有結果。

但如果分組測試的話,0x7E FF FF FF FF FF 是屬於 byte 6 的組別,那麼該組的測試最快會比原來方法快 4 倍。

PS: 一個字的測試差別不太,可是一篇文章有幾十萬個字,其中繁簡相同的字必定有很多,所以分組的方法比較可取。

相關連接:
ByteMap 是什麼?
讓程序自動編寫程序

Profile picture
斟酌 鵬兄
Tue Oct 20 2015 09:25:43 GMT+0000 (Coordinated Universal Time)
Last modified: Tue Oct 20 2015 16:16:36 GMT+0000 (Coordinated Universal Time)
Comments
No comments here.
Do you even comment?
website: 
Not a valid website
Invalid email format
Please enter your email
*Name: 
Please enter a name
Submit
抱歉,Google Recaptcha 服務被牆掉了,所以不能回覆了