輸入法開發實驗:地理資訊輸入法(一)
(註:其實這應該要畫很多圖來說明的,在此先略)
ilya先前和我討論到:有沒有可能拿OpenVanilla來做地理資訊的輸入工具?他的需求,簡單說來,有以下兩類:
- 輸入中文地名,出一地的英文地名或古地名
- 輸入中文地名,出一地的經緯度或其他座標資料
在和ilya以及中研院OpenGIS Lab的張欽隆討論後,我們決定將這個輸入法的開發,變成一種公開的實驗。
這篇文章便是這一系列實驗的第一篇。我的初步構想是:藉這個機會,來實現OpenVanilla最初設計的其中一個理想──簡化輸入法的開發過程,讓開發者能專心於輸入法的邏輯和演算法,而不需煩心於各種作業系統平台的實作細節。
同時,我也希望藉由這個實驗,來說明OpenVanilla晚近加入的一個新設計──所謂的「詞彙管理架構」,以及為什麼詞彙管理架構能夠填補現有輸入法設計的不足。
最後,也希望藉由這個實驗,來走一遍一個 open source project 的開發流程,包括了建立程式碼的版本管理倉庫、選擇版本授權等等雖然屬於「周邊」(peripheral)、但對於計劃延續不可或缺的部份。
問題分析
地理資訊的輸入是一件麻煩的事。由於與一個地名相關的資訊種類繁多,如果能以「地名」為中心,也就是拿地名來當key,便能輸入各種資料,對於地理相關工作應該是很有幫助的。Ilya的需求是由此出發的。
同時,地名也是一種有歷史性(historicity)的東西。地名不只是現時、此刻的存在,也代表了歷史的累積。打當今地名而能出古地名的需求,也是由此而衍生出來的。
輸入法所可能提供的協助
輸入法在軟體工程上是一種奇特的存在。雖然輸入法最早是輸入亞洲語文所不可或缺的工具(sine qua non)[1],但是本質上輸入法是一種變換(transform):輸入一串組字鍵碼,得出組字結果。嚴格說來輸入法其實就是一種索引鍵─鍵值(key-value)的查找關係。
而,因為輸入法在現代桌面環境上,可以與任何需要文字輸入的GUI元件共同工作,於是很奇異的,輸入法變成一種增加軟體功能的方法。也就是說,藉由擴充輸入法的功能,我們等於同時也擴充了應用程式的功能(簡繁轉換及標點符號轉換均為其例)。因此,輸入法可以被當成一種「非侵入式的外掛」(non-intrusive plug-in)。
然而,由於主流的輸入法架構,僅僅作到一次性的key-value查找(例如:以倉頡組字碼找中文字),因此就算我們打出了「台北」兩字,我們依然只能把這兩個字剪貼到另一套資料庫程式,藉以檢索與「台北」兩字相關的地理資訊。
OpenVanilla早期設計了所謂的「輸出過濾器」(output filter)的架構,是可以針對「以詞為輸出單元的輸入法」(例如酷音,每一次輸入都是一個詞)做輸出處理。例如,我們可以設計一個「打『台北』出Taipei」filter。然而過濾器的缺點是:在UI邏輯上,filter是一種單向的、多對一的(one-direction, many-to-one)轉換。對於地理資訊來說,我們需要一個反饋的過程,亦即,當打完「台北」之後,我們可能要讓用戶再一次選擇與「台北」相關的地理資訊。
這種類似「二次選字」的事情,用filter是無法做到的。
OpenVanilla的詞彙管理架構
OpenVanilla於2006年初提出了「詞彙管理架構」。事實上一套「詞彙管理架構」是由兩個元件組成的:置如輸入法之前的「鍵碼前置處理器」(Key Preprocessor)跟「詞彙補捉器」(Phrase Catcher)。詞彙補捉器其實是一個filter,只是不停地把使用者輸入的文字給收集進來。
這樣的好處是,讓非以詞彙為輸出單位的輸入法(例如倉頡,一次只輸出一個字),也能夠收集詞彙。而,透過置於輸入法之前的「鍵碼前置處理器」,我們可以在還沒進到輸入法之前,就先對使用者的按鍵做處理:例如,把從「詞彙補捉器」收集來的詞,丟進資料庫裡,或是拿來查找。
也就是說,透過 key preprocessor ,我們可以做到一個「超輸入法」(meta-input method),讓使用者可以用任何一種輸入法打完「台北」兩個字,然後再拿「台北」兩字做一些事。
由於 key processor + phrase catcher 這樣的架構可以做到「再一次的查找與轉換」,我們的地理資訊輸入需求,似乎可以再利用(reuse)這個 pattern 來達成我們的需求。
實作的方法
通常,在原型階段,我們會先用一些 dirty hack 以及 top-down approach ,很快地把程式的功能原型寫出來,來證明概念可行。在此之後,我們再改走 bottom-up approach ,細細烹煮(cook)每個所需的元件,最後再放到一起大火快炒,勾芡上桌。
由於設計樣式已經有了,這個設計也被證明可行,我們要做的是依照需求,重寫一套依地名查找地理資料的輸入法。
在此之前,我們得先把一些材料準備好。
材料:地理資訊的 XML 資料表
我們收到的是一份長相如下的 XML 資料表:
<place id='1'> <zh_name>漁人</zh_name> <en_name>Yuren</en_name> <lon>121˚ 32' 40"</lon> <lat>22˚ 1' 5"</lat> </place>
以上是該 XML 資料表的簡化版,我們先列出中文地名、英文地名與經緯度四項資料。
生的XML資料並不是那麼好利用。OpenVanilla推薦使用SQLite3。因此我們得先把XML煮成SQLite3能用的資料。
最懶的方法:XML::Simple
煮 XML 文件的方法很多,最懶又最快的方法,當然是使用 Perl 的 XML::Simple 模組了。
#!/usr/bin/perl -w use strict; use XML::Simple; my $filename=shift or die "Must specify a filename"; my $data=XMLin($filename);
嗯,好像這樣就煮完了,似乎沒什麼挑戰性。當然,如果你只裝 XML::Simple ,在 OS X 上可能會發生一些問題(XML::Simple 預設的 XML parser 是 XML::SAX::PurePerl ,在 UTF-8 判斷上似乎有點 suck),因此建議再安裝 XML::SAX::Expat ,就會順心如意多了:
sudo cpan install XML::SAX::Expat sudo cpan install XML::Simple
然後是怎麼轉換到 SQLite3 的問題。比較笨的作法是用 Perl 的 DBI 模組,然後實際開啟一個 SQLite3 資料庫,把轉換好的 $data 依欄位一個一個寫進去。
但是,這樣做,就實在太不懶惰了。SQLite3 的好處是,我們完全可以把資料生成另一堆生的 SQL 指令,然後讓 SQLite3 來吃。因為對 SQLite3 來說,一個資料庫就是一個檔案,所以萬一不高興,反正砍掉重練就是了。
所以,我們把煮成了 Perl hash 的資料一個個倒出來:
my $places=$data->{'place'}; for my $x (sort(keys(%$places))) { my $d = $places->{$x}; print "INSERT INTO geoinfo (zh_name, en_name, lon, lat) VALUES (", sqlquote($d->{zh_name}), ", ", sqlquote($d->{en_name}), ", ", sqlquote($d->{lon}), ", ", sqlquote($d->{lat}), ");\\n"; }
也就是說呢,我們把資料 dump 成一條又一條的 SQL INSERT 指令。
那個 sqlquote 是一個小的函數,幫忙我們把字串加上 SQL 的 quote:
sub sqlquote { my $x=shift; $x =~ s/\\'/\\'\\'/g; return "'$x'"; }
然後,我們在倒資料前,先加上建立資料庫 schema 和 index 的指令:
print "CREATE TABLE geoinfo (zh_name, en_name, lon, lat);\\n"; print "CREATE INDEX idx_zh_name ON geoinfo (zh_name);\\n"; print "BEGIN;\\n";
並在最後加上
print "COMMIT;\\n";
之所以要用 SQL transaction 來做插入,是因為 SQLite 在 non-transaction insert 的表現慢得嚇死人。用了 BEGIN…COMMIT 之後大體上會瞬間完成所有 insert 的動作。
好了,這樣差不多了,只要再做點水管工(plumbing),我們就可以把 XML 檔案轉成 SQLite3 的 DB 了:
./gendb.pl source.xml | sqlite3 geoinfo.db
從這裡開始……
我們還沒談到去哪找地方放這些程式的問題,因此目前還不會有可以下載的地方。有了資料庫,我們就可以開始想想怎麼設計輸入法了。希望我很快就有時間來寫下一篇。
註解
- T. C. Chiang, D. Liu, K. M. Liu, W. Z. Yang, P. T. Tan, M. J. Hsieh, T. H. Chang, W. L. Hsu, “OpenVanilla – A Non-Intrusive Plug-In Framework of Text Services”. 2005. (Abstract).
lukhnos :: Jun.29.2006 :: tekhnologia 技術或者藝術 :: 11 Comments »
11 Responses to “輸入法開發實驗:地理資訊輸入法(一)”
[...] http://lukhnos.org/blog/zh/archives/335 [...]
[...] [lukhnos(http://lukhnos.org/blog/zh)] 和 [ilya(http://ilyagram.org)] 提出「[地理資訊輸入法(http://lukhnos.org/blog/zh/archives/335)]」的想法,這其實是很有發展潛力的東西。如果利用這套輸入法,我可以在 [google earth(http://earth.google.com/)] 或 [OpenGIS(http://www.opengeospatial.org/)] 這類地理資訊系統簡單輸入地名,就會自動轉換成經緯度,顯示出地理位置以及其他資訊,充分展現出懶人智慧的精神。 [...]
有太嗨的感覺,說不定這也可以寫一個paper
想問一下,註解裡面的那篇文章,能否給個較完整的 citation form?另外,註解裡面列了八位作者,但 PDF 裡面卻只有兩位?
糟糕,我沒用過 MLA 以外的 citation format 的事實,馬上露了餡。
That is a defect, I’ll fix it later today.
William,
作者不一致的情況是因為當初那份文件有兩個版本,我剛剛把它們合併了:http://arxiv.org/abs/cs.HC/0508041
Citation form 部分,lukhnos 其實只漏寫了上頭那個 url,因為這份文件只發表在 arXiv.org 上。
關於那個 url,citebase 上提供的 BibTex 裡則使用這個 link:
http://www.citebase.org/cgi-bin/citations?id=oai:arXiv.org:cs/0508041
但該連結還沒反應出我才剛改版過的事實。
職業病,挑幾個小問題。 :)
文章第一頁倒數第二段:”Using input methods is the solution …”,建議將 “the” 改成 “a” 或類似的說法。
文章的第四頁 “Showcases” 的第一段指出:”… Xcin project, the first open-source project that offers various Chinese input methods on X11.” 不過如果我的印象沒錯的話, cxterm 應該比 Xcin 更早,至少當年我將行列輸入法移到 cxterm 上面時,Xcin 還沒出生。
另外,整體而言,這篇文章缺少了些 OpenVanilla 的架構圖及解說。或許是因為這篇文章你們只想著重在 HCI 部份,還不想觸及太多工程層面;不過既然標題已經出現了 “framework” 字眼,我建議還是該稍微談一下。
William,
非常感謝您當了義務審稿者 XD
那篇文章的完成度不太夠,最近會緩慢地更新;另一方面,下個月應該會有一篇十頁的、內容部分重疊但著眼點不同的相關文章出現。裡面就有張架構圖了。該圖目前在 http://flickr.com/photos/lukhnos/154762302/ ,越俎代庖地也請您多多指教了。
[...] cahier lukhnos (nota lumina) » 輸入法開發實驗:地理資訊輸入法(一) (tags: Tech InputMethod OpenVanilla) [...]
[...] 第一次對 arXiv 網站有點印象的,是在 lukhnos 那邊看到一篇 OpenVanilla 論文時,突然對這篇論文的展示處感到好奇:“arXiv”?這是什麼怪地方啊? [...]
[...] 幫 GVOzh 全球之聲中文翻譯計畫申請了 GVOzh 的 twitter 帳號,掛上了繁體/正體中文與簡體中文兩個 RSS feed,現在應該可以透過 twitter 帳號在任何地方收到最新的文章訊息了。下一步是要把文章自動加上 twittermap 空間標籤語法 L: 的地點 code:這樣當初我在 platial 上面想要作「全球之聲新聞地圖」(GVO News Worldmap)(失敗的構想 )的願望就終於可以實現了(曾經跟 Lukhnos 討論地理資訊輸入法,就是在解決類似的使用者情境)。 [...]