Skip to content

演算法缺陷導致s2twp「正則表達式=>正規表示式」無作用 #475

Open

Description

@danny0838

如題,雖然 TWPhrases* 有定義「正則表達式=>正規表示式」,但實際使用會把「正则表达式」轉成「正則表示式」。

我看不太懂C的程式碼,但就目前s2twp的配置檔看起來,程式似乎是先根據 STPhrases.ocd2 分詞,然後再對分詞後的片段做簡繁轉換和地區字詞轉換。由於 STPhrases 已經有「表达式=>表達式」一詞,原文會被切成「正则 表达式」,之後簡轉繁成為「正則 表達式」,由於已被切開,因此TWPhrases* 定義的「正則表達式=>正規表示式」無法匹配。

演算法可能需要改進,否則只有在STPhrases加入「正则表达式=>正則表達式」才能解決此問題。

Activity

  1. sgalal commented on Jul 2, 2020

    @sgalal
    Contributor

    目前程式的分詞和轉換都是正向最長匹配。

    我目前使用的解決方法是將轉換拆成兩個步驟,類似於將

    opencc -c s2twp

    改為

    opencc -c s2t | opencc -c t2twp

    這樣兩個步驟分別使用兩個詞典分詞,就不會出現這個問題。

  2. danny0838 commented on Jul 2, 2020

    @danny0838
    ContributorAuthor

    如果是這樣,那直接把 s2twp 裡面的 segmentation 拿掉就可以了。

    但我猜原來加入這個分詞機制是有原因的,應該是為了避免 s2t 以後 t2twp 在不適當的地方分詞。比如 s2t 詞表有「万用字元=>萬用字元」、「数据=>數據」,t2twp 詞表有「數據=>資料」「元數據=>後設資料」,那麼「万用字元数据有问题」就會在轉成「萬用字元數據有問題」之後被轉成「萬用字後設資料有問題」。

    所以才會先用 s2t 詞典切詞,讓原句變成「万用字元 数据 有问题」,簡轉繁後變成「萬用字元 數據 有問題」,以避免「元數據」被轉成「後設資料」的問題,結果輸出為「萬用字元資料有問題」。

  3. BYVoid commented on Jul 8, 2020

    @BYVoid
    Owner

    更好的辦法應該是改進分詞算法,使之不再依賴單獨的詞典分詞。可以依據整個詞典鏈來。

  4. danny0838 commented on Jul 14, 2020

    @danny0838
    ContributorAuthor

    更好的辦法應該是改進分詞算法,使之不再依賴單獨的詞典分詞。可以依據整個詞典鏈來。

    魔鬼藏在細節,問題在於怎麼實做。

    我想到的做法是先把詞典鏈裡的所有詞典合併成單一詞典,轉換時就用該合併詞典做轉換。

    因為合併時是把各組的詞典串聯生成更大的詞典,因此可以避免不適當的斷句,也可以說就是「根據整個詞典鏈」分詞。

    舉例來說,本來有 A 詞典組和 B 詞典組,首先先把各詞典組中的詞典「並聯」(全部載入及去重,類似目前的 merge.py 腳本)成 A 詞典和 B 詞典。

    然後再把 A 詞典和 B 詞典「串聯」,具體做法是合併以下兩組運算結果,即可生成合併詞典:

    • A 後聯 B:把 A 詞典的每個轉換結果用 B 轉換。例如 A 詞典有「为=>爲」,B 詞典有「爲=>為」,則轉換成「为=>為」。當然還要加上 B 本身的「爲=>為」。這主要處理 A 詞典輸出比 B 詞典輸入長的情況。
    • B 前聯 A:對於 B 的每組 x => y1, y2, ..., yn,透過 A 詞典的轉換表列舉出「所有經過 A 詞典轉換後會形成 x 的詞 x1, x2, ..., xm」,個別生成 x1 => y1, y2, ..., yn; x2 => y1, y2, ..., yn; ...; xm => y1, y2, ..., yn 的轉換組合。比如 A 詞典有「数=>數」「据=>據据」,B 詞典有「元數據=>後設資料」,則生成「元數據=>後設資料」「元数据=>後設資料」「元数據=>後設資料」「元數据=>後設資料」。這主要處理 A 詞典輸出比 B 詞典輸入短的情況。

    因為這個合併詞典是對「万用字元」「元数据」等詞直接做一次轉換,因此遇到像「万用字元数据…」的句子便不會像做兩次轉換的做法那樣把「万用字元」轉成「萬用字元」後又把「萬用字元數據」轉成「萬用字後設資料」。同理,也不會在遇到像「字符数据」這種句子時在轉成「字元數據」後又把「字元數據」轉成「字後設資料」。

    除此之外,這樣做還有其他好處:

    1. 合併詞典可以預先儲存起來,轉換時只需載入一個詞典、做一次轉換,可以提高載入速度和轉換速度。
    2. 由於實際上只需要一次轉換,因此很容易處理一對多或對轉換過的內容加標記。

    至於缺點……由於詞典串聯需要比較多運算,生成合併詞典速度會比較慢,而由於生成的詞組眾多,合併詞典檔案也會比較大,再加上每個轉換方案都要個別生成一個合併詞典,就會需要更多空間(如果即時組合,載入速度可能會慢到不能接受)。另外是這做法目前綁定「最大正向分詞」演算法,如果要改分詞演算法,則合併詞典的分詞演算法也會不同,則不能使用相同詞典,必須另外生成不同的合併詞典。

    實做方面,我寫的 Python 程式已經做出來了,可以參考。不過用 Python 寫的速度畢竟會比較慢,目前實測轉換文本大約需要 OpenCC 3 倍左右的時間。

  5. frankslin commented on Jan 19, 2026

    @frankslin
    Collaborator

    试了一下,改用「结巴」分词后,这个就可以正确处理了: https://opencc.js.org/compare?t=%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F

  6. frankslin commented on Jan 19, 2026

    @frankslin
    Collaborator

    不过正如 OP 所说,不改 mmseg 的分词算法,只需在 STPhrases.txt 里面加一条「正则表达式 -> 正則表示式」也应该可以解决这一问题了。词典里已经有「正则参数」的先例了:
    https://github.com/BYVoid/OpenCC/blob/733a9fe6bcd6a1dfaf0fd2b9dacbc2a52e7a65f6/data/dictionary/STPhrases.txt#L31070C1-L31070C5

    以后可要求 TWPhrases / TWPhrasesRev 中引入新词组时,添加 s2twp / tw2sp 测试;如果测试通不过,就需要再加 STPhrases 词组。

  7. danny0838 commented on Jan 19, 2026

    @danny0838
    ContributorAuthor

    結巴分詞不能真正解決問題,「正则表达式」之所以能正確處理,只是因為結巴的詞庫恰好有「正则表达式」這個詞,換成其他詞庫沒有的詞還是會出錯,比如,輸入反向的「正規表示式」,tw2sp_jieba 輸出的是「正规表示式」而非「正则表达式」。

    再如,TWPhrases 有個詞是「元數据↔後設資料」,但如果輸入「元数据」,s2twp 和 s2twp_jieba 都是輸出「元資料」,因為 STPhrases 有「数据→數據」,結巴詞庫也有「数据」,導致「元数据」被切成「元 數據」之後就無法順利轉換成「後設資料」。要避開此問題恐怕得額外把「元数据」加到 STPhrases 和結巴詞庫。

    此外,如果 輸入「後設資料」,tw2sp 會輸出「元数据」(正確),而 tw2sp_jieba 卻會輸出「后设数据」(錯誤)。結巴詞庫沒有「後設資料」這個詞,但輸入「後設資料」會切成「後 設資料」,導致「後設資料→元數据」的轉換失效。結巴詞庫並沒有「設資料」這個詞,為什麼這樣切我也不清楚,這又印證了之前說過的,分詞系統可預測性不佳的問題。


    在 STPhrases/TSPhrases 加詞並不是好方法,因為這兩個詞典本來就不是用於台灣地區詞轉換,把台灣地區詞專用的詞加進去會造成汙染,根本上就破壞了一開始分詞典的初衷,還可能導致其他使用同一詞典的轉換方案(例如 s2hk)發生非預期的錯誤。

    真要走這條路線,不如擴充 segmentation.dict 使之像 conversion_chain.dict 一樣接受多重詞典,然後把「元数据」之類需要額外加入的詞加到另一個檔案 STPhrasesTW.txt,並且把 s2twp 的 segmentation 改為用多個詞典分詞:

      ...
      "segmentation": {
        "type": "mmseg",
        "dict": {
          "type": "group",
          "dicts": [{
            "type": "ocd2",
            "file": "STPhrasesTW.ocd2"
          }, {
            "type": "ocd2",
            "file": "STPhrases.ocd2"
          }]
        }
      },
      ...

    這樣至少可以做到確實分離,但人工維護 STPhrasesTW, TSPhrasesTW 等詞典終究還是比較麻煩且易遺漏,最好還是能像我前面說的,直接改進演算法確實做到用整個詞典鏈分詞。

  8. frankslin commented on Jan 19, 2026

    @frankslin
    Collaborator

    理解你的意思了。config 中的 segmentation 现在就是支持 group 的,用法可如下述 diff。但是让它支持按「转换链中的最长匹配分词」,具体是怎么修改,语义上不太明确。根据我对算法的理解,分词和转换是两个步骤,分词阶段确立转换的边界。如果分词时没能把「元数据」当成一个词,就算后续词典链里有「元數據」,也匹配不上。假设真的能够把「链式转换」压缩成一次转换,不如直接把词表变成一个固定的、自动生成的一次转换对照表,最长匹配同时用于分词和转换。这会比修改算法把链式转换中某一层的「元數據 / ...」应用到输入字符串里的「元数据」容易得多。(当然之所以没有这样做,应该是因为这样做不可行。)

    这就是为什么现有机制下,一定需要给 STPhrases 里面加词才可以修好「元数据」的 s2twp 转换,而换用分词算法,有可能能解决一些未知词的问题(同时也可能因词表不同带来新的问题,这就要靠 regression test 来保证了)。

    diff --git a/data/config/tw2sp.json b/data/config/tw2sp.json
    index 64eb9d9..b66aed6 100644
    --- a/data/config/tw2sp.json
    +++ b/data/config/tw2sp.json
    @@ -3,8 +3,14 @@
       "segmentation": {
         "type": "mmseg",
         "dict": {
    -      "type": "ocd2",
    -      "file": "TSPhrases.ocd2"
    +      "type": "group",
    +      "dicts": [{
    +        "type": "ocd2",
    +        "file": "TSPhrases.ocd2"
    +      }, {
    +        "type": "ocd2",
    +        "file": "TWPhrasesRev.ocd2"
    +      }]
         }
       },
       "conversion_chain": [{
    
  9. danny0838 commented on Jan 19, 2026

    @danny0838
    ContributorAuthor

    前面的範例給錯了(已修改),應該是 STPhrases 等詞表才對,這裡不能直接把 TWPhrases.ocd2 加入,因為要加進詞表的是「元数据」而非「元數據」,甚至還要加上「元數据」、「元数據」等經過 STPhrases 轉換會恰好成為「元數據」的詞。

    換成 TSPhrases 同理,不能只是把 TWPhrasesRev 加入,這樣做雖然對「後設資料」的例子有效,但遇到 TSPhrases 詞較長的例子仍會失敗,要增加獨立的檔案才行。

    如前所述,我說的演算法已經用 Python 實現了,這裡也有線上版可測試(轉換方案選擇 oc/* 即是使用 OpenCC 1.1.9 的詞表),對於前述的「正则表达式」、「元数据」等例子目前都能正確處理。不否認可能還有我尚未想到的潛在問題使得本方案實際上不可行,不過目前為止還未有人提出過理由證明不可行,我就姑且當作只是還未實測過。

    Image

    Image

  10. frankslin commented on Jan 21, 2026

    @frankslin
    Collaborator

    检验了一下,以 TWPhrases.txt 的简体形式作为输入,使用 s2twp 进行下列转换,是有问题的
    (元数据->後設資料 已在 #1024 中修复):

    1. Line 9: SQL注入 → SQL注入 (預期: SQL隱碼攻擊)
    2. Line 10: SQL注入攻擊 → SQL注入攻擊 (預期: SQL隱碼攻擊)
    3. Line 13: 下拉列表 → 下拉列表 (預期: 下拉式清單)
    4. Line 19: 主引導記錄 → 主引導記錄 (預期: 主開機記錄)
    5. Line 33: 任務管理器 → 任務管理器 (預期: 工作管理員)
    6. Line 41: 信噪比 → 信噪比 (預期: 訊雜比)
    7. Line 101: 參數表 → 引數表 (預期: 參數列)
    8. Line 114: 喫茶小舖 → 吃茶小舖 (預期: 喫茶小舖)
    9. Line 159: 宏內核 → 宏核心 (預期: 單核心)
    10. Line 165: 審覈 → 稽核 (預期: 稽覈)
    11. Line 200: 所羅門羣島 → 索羅門群島 (預期: 索羅門羣島)
    12. Line 210: 捲積 → 卷積 (預期: 摺積)
    13. Line 233: 數據倉庫 → 資料倉庫 (預期: 資料倉儲)
    14. Line 234: 數據報 → 資料報 (預期: 資料包)
    15. Line 243: 文字處理 → 文字處理 (預期: 文書處理)
    16. Line 254: 時分複用 → 時分複用 (預期: 分時多工)
    17. Line 255: 時鐘頻率 → 時鐘頻率 (預期: 時脈頻率)
    18. Line 270: 桌面型 → 桌面型 (預期: 桌上型)
    19. Line 280: 正則表達式 → 正則表示式 (預期: 正規表示式)
    20. Line 289: 波分複用 → 波分複用 (預期: 波長分波多工)
    21. Line 309: 物理內存 → 物理記憶體 (預期: 實體記憶體)
    22. Line 310: 物理地址 → 物理地址 (預期: 實體地址)
    23. Line 339: 社區 → 社群 (預期: 社羣)
    24. Line 353: 空分複用 → 空分複用 (預期: 空間多工)
    25. Line 365: 純喫茶 → 純吃茶 (預期: 純喫茶)
    26. Line 388: 聯繫歷史 → 聯絡歷史 (預期: 通話記錄)
    27. Line 409: 處理程序 → 處理程式 (預期: 處理程序)
    28. Line 415: 複選按鈕 → 複選按鈕 (預期: 覈取按鈕)
    29. Line 416: 複選框 → 複選框 (預期: 覈取方塊)
    30. Line 424: 計算機安全 → 計算機安全 (預期: 電腦保安)
    31. Line 425: 計算機科學 → 計算機科學 (預期: 電腦科學)
    32. Line 429: 註冊機 → 註冊機 (預期: 序號產生器)
    33. Line 433: 調制 → 調製 (預期: 調變)
    34. Line 437: 調製解調器 → 調變解調器 (預期: 數據機)
    35. Line 485: 關係數據庫 → 關係資料庫 (預期: 關聯式資料庫)
    36. Line 493: 雲計算 → 雲計算 (預期: 雲端計算)
    37. Line 494: 面向對象 → 面向物件 (預期: 物件導向)
    38. Line 495: 面向過程 → 面向過程 (預期: 程序導向)
    39. Line 500: 預處理器 → 預處理器 (預期: 前處理器)
    40. Line 503: 頻分複用 → 頻分複用 (預期: 分頻多工)
    41. Line 505: 類模板 → 類模板 (預期: 類别範本)
    42. Line 512: 首席技術官 → 首席技術官 (預期: 技術長)
    43. Line 516: 馬里共和國 → 馬裡共和國 (預期: 馬利共和國)
    44. Line 517: 高性能計算 → 高效能計算 (預期: 高效能運算)
  11. danny0838 commented on Jan 22, 2026

    @danny0838
    ContributorAuthor

    检验了一下,以 TWPhrases.txt 的简体形式作为输入,使用 s2twp 进行下列转换,是有问题的 (元数据->後設資料 已在 #1024 中修复):

    實測提案的演算法輸出結果原則上是正確的:

    Image

    個別錯誤項目是因為 OpenCC 本來的辭典就有問題:

    • Line 165: TWPhrases 應輸出 稽核 而非 稽覈
    • Line 200: TWPhrases 應輸出 索羅門群島 而非 索羅門羣島
    • Line 339: TWPhrases 應輸出 社群 而非 社羣
    • Line 415: TWPhrases 應輸出 核取按鈕 而非 覈取按鈕
    • Line 416: TWPhrases 應輸出 核取方塊 而非 覈取方塊
    • Line 433: TWPhrases 應輸入 調製 而非 調制
    • Line 437: STPhrases 應輸出 調製解調器 而非 調制解調器
    • Line 516: STPhrases 應加上 马里共和国 → 馬里共和國 (否則 s2t 會轉成 馬(裏|里)共和國)

    這幾項應優先修正。

  12. frankslin commented on May 9, 2026

    @frankslin
    Collaborator

    除了按照 sts-lib 的做法对后级词条指数映射至前级,或者把全部 600 多条 TWPhrases key 的简繁版加入 STPhrases 外,又想到一个新办法。可以找出 TWPhrases 中有子串已存在于 STPhrases 的词条,只把它们加进 STPhrases 就好了。

    目前一共有 33 个词条,它们因分词在中间,没有起作用:

    Potential missing STPhrases entries for s2twp segmentation:
    TWPhrases key "SQL注入" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:32339 "注入" -> "注入"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "SQL注入攻擊" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:32339 "注入" -> "注入"
      The existing value appears as a middle fragment of the Taiwan phrase key.
    TWPhrases key "下拉列表" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:7952 "列表" -> "列表"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "主引導記錄" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:42941 "记录" -> "記錄"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "任務管理器" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:37752 "管理" -> "管理"
      The existing value appears as a middle fragment of the Taiwan phrase key.
    TWPhrases key "信噪比" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:4472 "信噪" -> "信噪"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "參數表" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:10651 "参数" -> "參數"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "宏內核" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:6098 "内核" -> "內核"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "彙編器" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:31735 "汇编" -> "彙編"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "數據倉庫" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:27051 "数据" -> "數據"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "數據報" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:26007 "据报" -> "據報"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "文字處理" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:16656 "处理" -> "處理"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "時分複用" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:16909 "复用" -> "複用"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "時鐘頻率" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:27907 "时钟" -> "時鐘"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "桌面型" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:30596 "桌面" -> "桌面"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "正則表達式" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:42331 "表达" -> "表達"
      The existing value appears as a middle fragment of the Taiwan phrase key.
    TWPhrases key "波分複用" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:16909 "复用" -> "複用"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "物理內存" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:34513 "物理" -> "物理"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "物理地址" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:34513 "物理" -> "物理"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "空分複用" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:16909 "复用" -> "複用"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "聯繫歷史" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:10404 "历史" -> "歷史"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "處理程序" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:16656 "处理" -> "處理"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "計算機安全" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:42867 "计算" -> "計算"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "計算機科學" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:42867 "计算" -> "計算"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "註冊機" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:32341 "注冊" -> "註冊"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "關係數據庫" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:5971 "关系" -> "關係"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "雲計算" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:42867 "计算" -> "計算"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "面向過程" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:47648 "面向" -> "面向"
      The existing value appears as a prefix fragment of the Taiwan phrase key.
    TWPhrases key "預處理器" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:16656 "处理" -> "處理"
      The existing value appears as a middle fragment of the Taiwan phrase key.
    TWPhrases key "頻分複用" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:16909 "复用" -> "複用"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "類模板" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:30890 "模板" -> "模板"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    TWPhrases key "首席技術官" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:24691 "技术" -> "技術"
      The existing value appears as a middle fragment of the Taiwan phrase key.
    TWPhrases key "高性能計算" is not covered by any STPhrases value.
      Conflicting STPhrases record: STPhrases.txt:42867 "计算" -> "計算"
      The existing value appears as a suffix fragment of the Taiwan phrase key.
    
  13. frankslin commented on May 9, 2026

    @frankslin
    Collaborator

    修正见 #1193

  14. added a commit that references this issue on May 9, 2026
    f12f6a0
  15. danny0838 commented on May 10, 2026

    @danny0838
    ContributorAuthor

    目前在 tw2sp/tw2s 也發現了一個同樣原理的錯誤:黃鍾公 => 黄钟公(應為 黄锺公)。

    我覺得這個 issue 不能那麼快關閉,因為根本的演算法問題還是在。目前的做法只是疊床架屋,用不太乾淨的 workaround 勉強讓 s2twp 可以比較順利的運作而已(而且還讓應該只在 TWPhrases.txt 的詞汙染到 STPhrases.txt)。未來如果增加 t2twp, s2hkp, hk2sp 之類的方案,或使用者嘗試自行增設詞庫,也都還是會出事。

  16. frankslin commented on May 10, 2026

    @frankslin
    Collaborator

    相比简转繁,繁转简相对容易一些,大部分情况都不需要在 TSPhrases 里面补词汇。

    我同意现在的做法只能作为不改算法情况下的一个 work around,TWPhrases 添加新词的过程目前仍比较繁琐。不过,我还是觉得 sts-lib 中的做法,把「數據庫」扩展成 2^3=8 种繁简混合的形式用于分词,有一些复杂。对于正常的待转换语料来说,繁简混写毕竟不是高频情况,直接用简体则可避免词表指数上升的问题。

    所以算法修改的思路,大概是把 TWPhrases.key 自动推导出的简体形式加入分词用表,与 STPhrases 一起使用,也就是模拟现在手动的操作。这样实现后,可以把不影响转换的映射从 STPhrases 中去掉了。当然,自动推导肯定不会 100% 完美,遇到特例情况,继续在 STPhrases 里手动加一下就好了。

    p.s.「黃鍾公」转换的问题,查阅作者金庸 1990 年代授权广州出版社的简体字版本,写的是「黄钟公」。中国大陆 1950 年代后把「鐘」「鍾」统一简化为「钟」,2013 年左右允许姓氏改回「锺」,但非姓氏的「鍾」字是否应改为「锺」似乎存在争议。此处「黃鍾公」作为虚构人物,其简体写法本身也已长期稳定使用。维基百科给他转换成「黄锺公」,不一定是对的。

  17. danny0838 commented on May 10, 2026

    @danny0838
    ContributorAuthor

    sts-lib 的演算法可以全自動化,且只需要依賴輸入的詞典,應該是最通用、最簡單、最好維護的做法。

    至於詞表指數上升問題,實測並不明顯。以膨脹可能性最大的 s2twp 為例,實際輸出檔案大小只增加了 2%:

    檔案 大小
    STPhrases.txt 1,009,194
    STCharacters.txt 34,615
    TWPhrases.txt 12,847
    TWVariants.txt 562
    以上總和  1,057,218
    s2twp.list  1,080,189

    以上測試為取最新版,把 s2twp.yaml 的 file 值改為 .../s2twp.list,執行 scripts/build.py 後檢查 opencc 的 build 結果(所有檔案統一使用 LF 換行)

    至於你說的方法,恐怕難點就出在如何從 TWPhrases.keys 推導簡化版本,如果依賴反向的 t2s 方案會造成複雜的依賴關係,況且你也知道 OpenCC 無法完美實現 s2t(t2s(x)) = x。又無論是自動檢查+人工建推導詞表,或自動推導+人工處理例外,都會增加維護負擔,使用者嘗試自訂詞庫或轉換方案也會非常麻煩。

    我會比較建議以 sts-lib 的演算法作為基礎、通用的自動推導方式,如果未來想優化,可再加入額外參數去改變自動推導的方式(例如改用不同的 t2s 推導方式,或外掛詞典檔,或外掛例外項目等等)。


    繁轉簡的問題是,使用 TSPhrases.txt 分詞本質上就是錯誤的(tw2sp 應該使用 twp,tw2s 應該使用 tw,而非 t),目前的分詞其實有和沒有一樣(只是 OpenCC 也不允許拿掉 segmentation)。雖然由於 TSPhrases 詞組少,因此還不容易遇到實例,但這就像是未爆彈,不知道未來會在加入什麼詞的時候爆炸。


    至於「鍾」的問題,《通用規範漢字表》附錄是這樣寫:

    鍾:用于姓氏人名时可简化作“锺”

    所以非姓氏的人名自然可以用「锺」。

  18. frankslin commented on May 11, 2026

    @frankslin
    Collaborator

    至於你說的方法,恐怕難點就出在如何從 TWPhrases.keys 推導簡化版本,如果依賴反向的 t2s 方案會造成複雜的依賴關係,況且你也知道 OpenCC 無法完美實現 s2t(t2s(x)) = x。又無論是自動檢查+人工建推導詞表,或自動推導+人工處理例外,都會增加維護負擔,使用者嘗試自訂詞庫或轉換方案也會非常麻煩。

    有一个几乎不用改 OpenCC 算法的办法,只要改一改 build 流程就行。

    1. 利用 t2s 模式把 TWPhrases.txt 转换为 TWPhrasesForSegmentation.txt
    2. 把 TWPhrasesForSegmentation.txt 编译成 TWPhrasesForSegmentation.ocd2
    3. 把 s2twp.json 的 segmentation 字典改成 group,同时看用 STPhrases.ocd2 和 TWPhrasesForSegmentation.ocd2

    繁转简方向,也可以进行镜像操作。

    tw2sp 的分詞表可改为加入 TWPhrasesRev、TWVariantsRevPhrases、TWVariantsRev,这个应该有立竿见影的效果。部署后可以直接用 opencc.exe --segmentation 或在线版本「查看分词」功能看分词点是否增加。

    "file": "TSPhrases.ocd2"

  19. danny0838 commented on May 16, 2026

    @danny0838
    ContributorAuthor

    作為暫時的 workaround 應該可行,不過還是要想辦法處理 s2t 和 t2s 不等價的問題,以及 t2s 如果是一對多的狀況。

    作為鏡像處理,tw2sp 的分詞表理論上要加入 TWPhrasesRev、TWVariantsRevPhrases、TWVariantsRev、和 T2SForSegmentationTW2SP 才行。而如果換成 tw2s 則要加入 TWVariantsRevPhrases、TWVariantsRev、和 T2SForSegmentationTW2S。

    如前所述,後者是未爆彈,目前似乎還沒有實例,可能要先人造一個詞用於測試。

  20. danny0838 commented on Jun 13, 2026

    @danny0838
    ContributorAuthor

    目前還是有不少漏洞,例如:

    方案 輸入 輸出
    s2twp 仙童半导体 仙童半导体厂
    人工智能 人工智能借用
    快捷半導體 仙童半導體廠
    人工智慧 人工智能借用
    tw2sp 畫素 畫素藉由
    圖示 圖示覆蓋
    像素 画素借由
    图标 图示复盖

    檢測腳本可參見 #1285 1ce0c16,大概有 500 筆有類似問題,大佬們加油吧。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions