CJK Tokenizer

英文的Tokenizer就已經有夠難寫了。再加上CJK的話,寫Tokenizer簡直就是人間地獄。

為了幫這個網站設立搜索功能,我一邊看完全沒有Documentation的Demo網站,一邊抄它的源代碼。還好最後只花了三個小時就寫好了,不算太難。

整個過程中最麻煩的莫過於搜索引擎的Tokenizer了。它預設的Tokenizer好像是以空格作為每個Token的分界,所以如果我們把一篇CJK的文章丢進Tokenizer的話,它就會把整篇文章當成一個大Token去處理。解決方法其實不難,只要把每個單字當成一個Token就可以了。雖然準確度不高,但是至少能搜索到文章。

不過,我的網站的文章不是全部都是中文。我有幾篇英文的文章,它們不適合用CJK的Tokenizer。

最後,我的Tokenizer代碼如下:

encode: str => {
    // to lower case
    str = str.toLowerCase()

    // remove html special characters
    str = str.replace(/&\w+;/g, "")

    // Why are there so many types of dashes
    str = str.replace(/ [-–]+ /g, " ")

    // remove non-language text
    str = str.replace(/[^ '\-a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]/g, " ")
    .replace(/\s+/g, " ")
    .trim()

    // Extract non-english
    let cjk = str.replace(/[\x00-\x7F]/g, "").trim()

    // Extract English (ASCII)
    let eng = str.replace(/[^\x00-\x7F]/g, " ").trim()

    arr = []
    if (cjk !== "") {
        arr = arr.concat(cjk.split(""))
    }
    if (eng !== "") {
        arr = arr.concat(eng.split(/\s+/g))
    }
    
    return arr

我決定結合CJK和英文的Tokenizer。不太完美,但是至少能跑。

不過,CJK Word Tokenizer應該永遠都會是未解之謎吧。(你能想像作文不用字數,而是詞語數量作標準嗎……)