輸入法引擎的模型設計


最近在寫《自表達代碼》一書,該書第22章將會介紹一個Android平台上的日文輸入法的開發過程。通過該開發過程展示如何在程序開發過程中保持代碼的可讀性、可擴展性和可變更性。

在寫該部分之前,首先需要進行輸入法引擎的設計。

下面是一個相對來說傻大笨粗的輸入法引擎設計思路。雖然傻大笨粗,但是由於數據量並不大,數據算法次數並不多,所以該設計仍然是“可以接受的”。即處理時間上比較快、存儲空間上占用不大。但是距離十分優秀的輸入法還有很長的距離要走。

 

輸入法的基本工作原理就是,輸入一堆英文字符,然后利用英文字符到一個字典中去查找英文字符應該翻譯成什么對應的自然語言文字。

這里提到的輸入法引擎就按照這個思路來設計的。

 

首先,輸入法的字典應該是一個二進制文件。

二進制文件中包含了這樣三部分內容。

1. 文件頭

      表述了一些基本信息,比如:索引的尺寸,字典的尺寸等。 假定為100字節。    

2. 索引

     用來加快計算速度的。但是由於雙字節語言(CJK)都是采用了長拼寫的方式,並且還有詞組的概念,所以這個索引會比較復雜。

     還會涉及到索引的索引。具體后續會討論。

3. 字典數據

     用來存儲具體的字典數據。

 

很顯然,這樣的數據結構是很容易被注入的,DOS下的一些病毒就是利用了文件分區表 的特點進行注入的。這個設計思路和文件分區表並無二致。

但是這里只是表明算法的基本思路,對於數據文件的保護可以通過其他的方式來進行,這里不做討論。

 

為了能夠更好的描述算法,從輸入的角度開始,而不是從技術的角度開始。

以中文為例,輸入zhuru,應該顯示注入,諸如,侏儒三個候選漢字詞組。

那么這個過程是怎么完成的呢?

 

首先,在索引中找zhu;然后,在zhu下面找ru;再然后在zhuru下找到詞組。

這聽起來很簡單,不是嗎?

那么在具體的技術中怎么實現的呢?

1. 索引中找zhu

    把中文的聲母 和韻母列成兩張表格

   聲母:b p m f d t n l g k h j q x zh ch sh r z c s w y

   韻母:a o e i u v ai ei ui ao uo ou ang eng ing ong an en in un vn iong...(還有很長)

   分別依次對這些符號進行編號,都采用2位數字

   比如:b = 01 p = 02..

            a= 01 o =02..

   那么zhu是多少呢? zh=15 u=05,那么zhu就是1505

   ok 那么zhu的偏移量就是 (15(zh的id) x (韻母的個數) + 05(u的id)) x 4(4字節為單位)。

   這個數字是干什么用的呢?100(文件頭的尺寸) + 這個數字(zhu的偏移量)可以定位到文件中的一個位置。

   假設韻母的個數是50吧(好算)

    (15 x 50 + 05 ) x 4 = 755 x 4 = 3,020

    再 + 100,就是3,120。

    找到3120這個位置,讀取4個字節,這4個字節是一個數字,這個數字是一個地址,這個數字表示了zhu開頭的所有拼音組合的索引的開頭地址。

    比如它就是600000吧,那么我們定位到600,000這個位置,這里記錄了zhua,zhuo,zhue,zhui,zhuu,zhuv等等所有的詞組的索引。

 

    然后,找到這個zhu開頭的所有的索引之后,直接定位到其中的ru的位置。

    怎么計算呢? 和剛才一樣,r=18, u = 05,ru就是1,805。

    然后ru的偏移量就是 (18 x 50 + 05) x 4 = 3,620。

    那么定位到603,620這個位置,從這個位置也讀取4個字節,它還是一個地址。比如就是5,000,000吧。

    這個意思是說5,000,000這個位置開始是zhuru的詞組,但是到底有幾個呢?所以,這個位置上來不是詞組,而是詞組的一些簡要信息,

    1個字節,表示數據的個數。那么,這里應該是3。然后向后依次讀取3 x (2 個漢字 + 3字節的詞頻) 。每2個字組成一個詞組,返回回來。

 

    這樣算下來,一共需要的計算是

     1. zhu的位置計算

     2. ru的位置計算

     3. zhuru的位置定位

     4. zhuru的信息讀取

     5. 詞組的讀取

     6. 詞組的分離

  這樣幾個步驟。可以達到秒殺了。

 

  然后,看看文件的尺寸,

  文件頭100字節

  索引的索引的尺寸 = 聲母數 x 韻母數 x 4字節 = 21 x 50 x 4 = 4,200字節

  索引的尺寸(按照只收錄2字詞組計算) = 索引的索引個數(第一個字) x 索引的索引個數(第二個字) x 4字節 = 4,410,000字節

  然后,平均每種組合有3個詞組(實際上會比這個略低一點,因為有很多拼音是不存在的,而且很多拼音是沒有詞組的)。

  數據的尺寸 = 索引的個數(第一個字) x 索引的個數(第二個字) x 3(個詞組) x (2個字/個詞組  + 3字節/詞頻 ) x 2字節/字 + 索引的個數 x 索引的個數 x 1字節 = 

                    (索引的個數 x 索引的個數) x ( 3 x (2 + 3)x 2 + 1) = 1050 x 1050 x 31 = 34,175,500 字節

 

  累加  100 + 4,200 + 4,410,000 + 34,175,500 = 38,591,800

  約36.8M字節。這還只是2個漢字的詞組。這是無法容忍的。

 

  上面的算法用下圖可以表示出來。

 

  所以,應當對詞典進行瘦身,也應當對算法進行改進。

 

  1. 由於每個拼音下面的漢字不會超過 256個,所以漢字可以用索引來代替,從而減少1個字節。

      需要另外建立一張漢字與拼音對照表。

  2. 重新認真的數一下韻母的個數

       a o e i u v ai ei ui ao ou iu ie ve er an en in un vn ang eng ing ong uan uang ian iao iang iong 

     共30個。

       另外,還有一個沒有聲母的情況。

  3. 從索引中排除那些肯定不會存在的拼音

      和v相拼的 bv pv mv fv dv tv gv kv hv jv qv xv zhv chv shv rv zv cv sv yv wv

      和vn相拼的 bvn pvn mvn fvn dvn tvn gvn kvn hvn jvn qvn xvn zhvn chvn shvn rvn zvn cvn svn yvn wvn

      和i相拼的gi ki hi wi

      和ie相拼的fie gie kie hie zhie chie shie zie cie sie yie wie

      和iu相拼的biu piu miu fiu giu kiu hiu zhiu chiu shiu riu ziu ciu siu yiu wiu

      和in相拼的fin din tin gin kin hin zhin chin shin rin zin cin sin win

      和ian相拼的fian gian kian hian zhian chian shian zian cian sian rian yian wian

      和iao相拼的fiao giao kiao hiao zhiao chiao shiao ziao ciao siao yiao wiao

      和iang相拼的biang piang miang fiang diang tiang giang kiang hiang zhiang chiang shiang ziang ciang siang yiang wiang

      和iong相拼的biong piong miong fiong diong tiong niong liong giong kiong hiong zhiong chiong shiong ziong ciong siong yiong wiong

      和un相拼的 bun pun mun fun nun

      和uo相拼的buo puo muo fuo juo quo xuo yuo wuo

      和uan相拼的 buan puan muan fuan wuan

      和uang相拼的buang puang muang fuang duang tuang nuang luang ruang zuang cuang suang yuang wuang

      和a相拼的ja qa xa ra

      和ai相拼的fai jai qai xai rai yai

      和an相拼的 jan qan xan

      和ang相拼的 jang ang xang

      和e相拼的je qe xe we

      和ei相拼的dei zhei chei shei cei sei yei

      和er相拼的ber per mer fer der ter ner ler ger ker her jer qer xer zher cher sher rer zer cer ser yer wer

      和en相拼的den ten len jen qen xen 

      和eng相拼的jeng qeng xeng yeng weng

      和o相拼的do to no lo go ko ho jo qo xo zho cho sho ro zo co so yo

      和on相拼的don ton non lon gon kon hon jon qon xon zhon chon shon ron zon con son yon won

      和ong相拼的jong qong xong yong wong

      和ou相拼的bou jou qou xou you wou

      (懶得數這有多少了,用程序計算了一下是292個。)      

     
      這需要犧牲算法時間為代價,因為不能僅僅通過offset來定位。(至於新算法也和老算法意思差不多,只是偏移形式重新規划要按照聲母 + 韻母進行偏移量計算,而不是分開計算。)

      22個聲母 x 30 個韻母 - 292 = 368個組合

      

按照新思路重新計算一下空間

1. 100 字節的文件頭

2.  368 x 4字節的索引的索引 = 1,472 字節

3. 368 x 368 x 4字節的索引 = 541,696字節

4. 368 x 368 x (3 x (1 + 3) x 2 + 1) =  3,385,600字節

累計為 3,928,868字節。容量已經縮減為3.7M左右了,是第一個方案的1/10左右。

之所以沒有一上來就提這個3.7M的方案是為了能夠先描述清楚思路。另外,對於這個方案還有瘦身的余地,但是思路已經描述清楚,就不再繼續瘦身了。

 

好了,至此,一個簡單的文字翻譯引擎就設計完了。

 

只輸入的時候xian是如何變成xian和xi'an兩種組合的,則不在詞典檢索范疇來做,而是在輸入端進行控制。

這個時候詞頻表的作用就體現了。

   

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM