The Old Blog Archive (Traditional Chinese), 2004-2009

輸入法開發實驗:地理資訊輸入法(一)

(註:其實這應該要畫很多圖來說明的,在此先略)

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

從這裡開始……

我們還沒談到去哪找地方放這些程式的問題,因此目前還不會有可以下載的地方。有了資料庫,我們就可以開始想想怎麼設計輸入法了。希望我很快就有時間來寫下一篇。

註解

  1. 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).

11 Responses to “輸入法開發實驗:地理資訊輸入法(一)”

  1. [...] http://lukhnos.org/blog/zh/archives/335 [...]

  2. [...] [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/)] 這類地理資訊系統簡單輸入地名,就會自動轉換成經緯度,顯示出地理位置以及其他資訊,充分展現出懶人智慧的精神。 [...]

  3. on 29 Jun 2006 at 11:08acer

    有太嗨的感覺,說不定這也可以寫一個paper

  4. on 29 Jun 2006 at 13:00william

    想問一下,註解裡面的那篇文章,能否給個較完整的 citation form?另外,註解裡面列了八位作者,但 PDF 裡面卻只有兩位?

  5. on 29 Jun 2006 at 13:07lukhnos

    糟糕,我沒用過 MLA 以外的 citation format 的事實,馬上露了餡。

    That is a defect, I’ll fix it later today.

  6. on 29 Jun 2006 at 14:57b6s

    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

    但該連結還沒反應出我才剛改版過的事實。

  7. on 29 Jun 2006 at 22:10william

    職業病,挑幾個小問題。 :)

    文章第一頁倒數第二段:”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” 字眼,我建議還是該稍微談一下。

  8. on 30 Jun 2006 at 01:18b6s

    William,

    非常感謝您當了義務審稿者 XD

    那篇文章的完成度不太夠,最近會緩慢地更新;另一方面,下個月應該會有一篇十頁的、內容部分重疊但著眼點不同的相關文章出現。裡面就有張架構圖了。該圖目前在 http://flickr.com/photos/lukhnos/154762302/ ,越俎代庖地也請您多多指教了。

  9. on 04 Jul 2006 at 08:25-TMA-1- » links for 2006-07-04

    [...] cahier lukhnos (nota lumina) » 輸入法開發實驗:地理資訊輸入法(一) (tags: Tech InputMethod OpenVanilla) [...]

  10. [...] 第一次對 arXiv 網站有點印象的,是在 lukhnos 那邊看到一篇 OpenVanilla 論文時,突然對這篇論文的展示處感到好奇:“arXiv”?這是什麼怪地方啊? [...]

  11. [...] 幫 GVOzh 全球之聲中文翻譯計畫申請了 GVOzh 的 twitter 帳號,掛上了繁體/正體中文與簡體中文兩個 RSS feed,現在應該可以透過 twitter 帳號在任何地方收到最新的文章訊息了。下一步是要把文章自動加上 twittermap 空間標籤語法 L: 的地點 code:這樣當初我在 platial 上面想要作「全球之聲新聞地圖」(GVO News Worldmap)(失敗的構想 )的願望就終於可以實現了(曾經跟 Lukhnos 討論地理資訊輸入法,就是在解決類似的使用者情境)。 [...]