BYVoid / OpenCC

Conversion between Traditional and Simplified Chinese
https://opencc.byvoid.com/
Apache License 2.0
8.3k stars 974 forks source link

請問是否有方法可以找出 OpenCC 無法識別的生字? #852

Closed doggy8088 closed 4 months ago

doggy8088 commented 4 months ago

我想要補充一些自訂詞彙到我自己的 OpenCC 自定義字典中,但是一直沒辦法找到一個很有效率的方法可以找出文章中無法被 OpenCC 識別的詞彙。請問是否有什麼方法可以快速找出 OpenCC 無法識別的生字?

danny0838 commented 4 months ago

請問哥怎麼定義所謂的「詞彙/生字」以及「無法識別」?

舉例來說,對於短句「头发白了」:

doggy8088 commented 4 months ago

不好意思,我的問題可能不夠精確。

我的概念是這樣,要能夠做詞彙的轉換,首先要能夠斷詞,因為 OpenCC 有自己的一套斷詞系統,我只是想知道 OpenCC 的斷詞結果,這樣才能知道數萬個詞庫是否有哪些需要補充的地方。

doggy8088 commented 4 months ago

我以您的「头发白了」為例進一步解釋:

data/config/s2twp.json 的定義是這樣的:

{
  "name": "Simplified Chinese to Traditional Chinese (Taiwan standard, with phrases)",
  "segmentation": {
    "type": "mmseg",
    "dict": {
      "type": "ocd2",
      "file": "STPhrases.ocd2"
    }
  },
  "conversion_chain": [{
    "dict": {
      "type": "group",
      "dicts": [{
        "type": "ocd2",
        "file": "STPhrases.ocd2"
      }, {
        "type": "ocd2",
        "file": "STCharacters.ocd2"
      }]
    }
  }, {
    "dict": {
      "type": "ocd2",
      "file": "TWPhrases.ocd2"
    }
  }, {
    "dict": {
      "type": "ocd2",
      "file": "TWVariants.ocd2"
    }
  }]
}

依據我的理解,斷詞(segmentation)會先完成,然後才做轉換(conversion_chain)。

斷詞載入的是「STPhrases.ocd2」詞彙檔,所以本質上是 data/dictionary/STPhrases.txt 定義檔。

所以,因為「头发」在斷詞檔中有出現,所以會先被分出來,因此「头发白」與「发白」是不可能被轉換的,就算出現在轉換表中也沒用,定義了就是無效的轉換詞彙。(我實務上常會遇到不知道定義有沒有效的狀況,所以想知道有沒有工具可以快速判斷)

而「白了」並不在斷詞檔中,所以「有機會」被轉換成其他的詞彙。

對我來說,所謂「無法識別的生字」就是沒有成功被「斷詞」的那些文字內容,因為透過 OpenCC 進行簡繁轉換時,只有那些「沒有被斷詞」的詞彙可以被轉換詞彙。如果分的夠好的話,理論上連「詞彙轉換」都不需要自定義。

以上是我對 OpenCC 的理解,不是很確定是否理解正確,也不是很確定是否有其他「分詞」或「斷詞」的設計在內,所以想請教一下。

danny0838 commented 4 months ago

分詞方面目前看起來就如您所述,而且我之前就發現過有相關 BUG (#475),但目前一直沒人處理。

以現況來說,如果您只是想知道輸入的詞是否會被 STPhrases.ocd2 切詞,那最簡單的方法不就是自己寫個程式載入 STPhrases.ocd2 (或 STPhrases.txt) 並按之切詞看看即可?

doggy8088 commented 4 months ago

我因為沒特別研究過 OpenCC 的原始碼,所以不確定分詞方式是否有用到什麼特殊的演算法,例如透過統計分析計算詞頻之類的,所以不敢貿然下定論。

請問 @danny0838 是否瞭解這個部分?還是說 OpenCC 目前僅對分詞表中的字串進行比對而已?

danny0838 commented 4 months ago

mmseg 就是正向最大匹配法,有分簡單和複雜版,複雜版是在簡單版分詞的基礎上再加上幾個經驗法則,以求取出更自然的分詞,細節Google一下就有,但是用在簡繁轉換似乎反而可能會讓結果更難以預測,而且完整的複雜版實做需要有詞頻庫,目前 OpenCC 應該沒有。最早以前 OpenCC 好像是用複雜版,但近來的版本看起來似乎都是簡單版的,至少和我之前自己實做的轉換看起來結果沒有明顯差異。

OpenCC 目前只提供直接轉換文字的 API,諸如一對多轉換的處理或標記、分詞都沒提供,我一直覺得很可惜。您如果懂 C 的話,應該可以直接研究原始碼,看是直接呼叫相關的內部函數,或改一些程式碼把它做成開放的 API 都可以。

doggy8088 commented 4 months ago

@danny0838 我今天用 C# 重新實作了 mmseg 演算法 (正向最長匹配),分詞應該算是搞定了,我現在可以很輕易的找出沒有分詞的中文句子,非常感謝您的幫助。 😊

danny0838 commented 4 months ago

我後來想到,以實際使用的角度來說,通常會有加詞無效的問題,就是像之前那個 issue 一樣把詞加在 TWPhrases 但分詞詞典是 STPhrases 而造成的問題,那建立新詞時只要也加在 STPhrases 應該就可以確定不會發生加詞無效。好像也沒有非要特別寫程式處理?

不過當然如果能用程式重新根據 STPhrases 或 TWPhrases 分詞,或許可以比較快發現一些需要特別處理的詞也說不定。

doggy8088 commented 4 months ago

分詞做的好,對於比較短的詞(尤其簡體字特別多這類詞)轉換品質才會好。

例如:「包」應轉換為「套件」,「类」應轉換為「類別」,但這種單字的轉換,透過 OpenCC 非常難定義,原因還是出在分詞部分。

我自己嘗試將分詞詞典擴充到百萬項,轉換的品質就好的非常多。目前 STPhrases.txt 只有 49,058 筆,很多詞都沒辦法分好,這時靠 Conversion 就很難做到精準轉換。

danny0838 commented 4 months ago

維基百科其實就有相當大的詞庫,不過和OpenCC 追求的區分繁簡轉換與地區轉換有別,無法直接使用。

但是要擴充詞庫又受前面那個「只能有一個分詞詞典」的問題限制,變成擴充任何地區詞詞典都必須在簡繁詞典加上對應的詞,目前很尷尬。

如果要照原來的分詞架構,演算法的部分可以試試看我寫的套件是否能解決。如果確定能解決,看您是否有意願把該套件的邏輯轉寫成C以適用此專案。😆

不過因為我之前提的一大堆強化轉換庫(主要是簡繁轉換的字庫和詞庫)的PR還未處理,在master後面自行擴充的版本基本就和OpenCC沒有一致了。