-
-
Notifications
You must be signed in to change notification settings - Fork 1k
關於「發 / 髮」在部分雙向詞彙下的語意轉換問題 #1059
Description
在使用 OpenCC 簡繁轉換的過程中,發現有「發 / 髮」幾個詞彙(乱发、发色、生发、额发...)在處理時,比較容易出現語境上的歧義。
針對這部分,我整理了一些觀察與邏輯拆解的心得,看看是否能透過增加一些上下文的邏輯處理,來讓轉換效果更細膩一些。
1. 問題觀察:對應的限制
在目前的 OpenCC 轉換中,這四個詞預設限定轉為「髮」:
- 乱发➡️亂髮 (一對一)
- 发色➡️髮色 (一對一)
- 生发➡️生髮 生發 (一對二)
- 额发➡️額髮 (一對一)
但在實際語境裡,它們往往具備兩種以上的意思:
乱发 :可能是「一頭亂髮」(名詞),也可能是「亂發脾氣、亂發文章」(動詞行為)。
发色:可能是「頭髮的髮色」(形容詞),也可能是「螢幕的發色表現」或「亂發色情內容」(技術或行為)。
生发:可能是「生理上的生髮」(名詞/產品),但也會出現在「學生發明、研究生發現、人生發展」或是古文中的「賊寇生發」(主體+動詞)。
额发 :預設為「額髮」,指額頭前的頭髮(名詞)。但在工商業或行政公文中,也會出現「XX 額 + 發 + 動作/數字」的組合,例如「足額發放」。
其中「生发」雖有一對二的設定,但我在使用「OpenCC 轉換工具演示」時,試著用辭典書裡的句子像
「见先生发怒」 或 「鼓励学生发现原则的教学方式」,
不論哪個選項或有無使用結巴分詞,都是轉為
「見先生髮怒」 或 「鼓勵學生髮現原則的教學方式」,
我不是很確定要如何設定才會出現第二種轉換的結果(生發)。
這讓我思考,單靠辭典的「長詞優先」或「多選一」可能還不夠,或許我們需要透過「上下文」來協助處理這類語意分歧。
2. 拆解與重新定錨的邏輯
為了提升辨識度,我嘗試透過檢查「前字」與「後字」來重新定義這些詞的屬性:
- 「乱发」的動態過濾:
觀察「亂發」後方的受詞。若後方接的是「脾氣、瘋、財、貨、文章、郵件」等受詞,則判定為 「發」。若後端不符合這些動作特徵,則回歸到 OpenCC 預設的 「亂髮」。
- 「发色」的語境分流:
技術判定:若前方出現「螢幕、面板、顯示器」等特定名詞,則判定為硬體顯色的 「發」。
生理回歸:若非以上兩者,則回到 OpenCC 預設視為顏色的 「髮色」。
- 「生发」的主體辨識:
這裡最關鍵的是區分「身分」。當「生」作為身分結尾(學生、醫生、先生)時,後方的「發」往往接續著「揮、明、現、展、表、郵、帖」等詞。有些靠內建(揮),有些是需要額外增加(郵)。
此外,若前前字出現「賊、寇」,則屬於歷史語境中的禍亂產生,也要轉為「發」。排除這些情況後,再回歸為預設的 「生髮」。
- 「额发」的綜合判定:
數額判定:觀察前前字(pp)是否具備「足、滿、差、定、員、稅」等數額特徵。
動作/數值定錨:若後方接續「工、補、證、料、債、不」等給付動作,或直接緊跟著「數字(m)」,則判定為動詞行為的 「發」。
3. 效果分析
關於上述的這套語法邏輯不敢說能處理 100% 的情況,但經過初步測試與分析,針對這一些特定詞彙,保守估計能改善五、六成以上在原本轉換下會出現的問題。
AI 產生的測試句:萤幕发色异常时,那个研究生发挥专业,没对发卷宗的老师乱发邮件,因为看到留学生发表了关于生发水的论文,自己也要为人生发展而努力...
參考結果:螢幕發色異常時,那個研究生發揮專業,沒對發卷宗的老師亂發郵件,因為看到留學生發表了關於生髮水的論文,自己也要為人生發展而努力...
由於我個人對程式語言不太熟悉,因此目前的邏輯是讓 AI 以 EmEditor Macro (JavaScript) 的形式來呈現,便於日常使用,也便於測試。
雖然 OpenCC 的核心是 C++,但這種上下文的邏輯,我覺得或許是可以移植到 C++ 的辭典預處理或轉換引擎中的。
在效能方面的考量上,這套邏輯只會在遇到關鍵字(如「發」、「生」),且原本內建的辭典未轉換時才會執行判斷,不會對所有文字進行複雜運算。
實際測試在處理 1GB 的文字檔案,六百多萬行,進行簡轉繁三千六百多萬處,轉換時間的差異僅在 1 秒上下。
考量到以小小的時間差異,以及壓縮後增加一行的程式碼,能換取更精準的自動轉換結果,減少後續的人工校對,我覺得或許是可以嘗試的優化方向。
如果直接窮舉「亂發脾氣、學生發帖、醫生發郵件、限額發債...」等所有詞條全部放進詞庫,雖然也能解決。但動詞、名詞甚至加上數字的排列組合,會導致詞庫非常龐大。
這邊是我跟 AI 多次反覆討論出來的常用字語意邏輯之一。
過程有點一言難盡,因為 AI 常常會「自作聰明」亂改程式,或是把辭典裡原本就有的詞又寫進來造成冗餘,有時又會幻想出根本沒有的詞語組合。
所以這份程式碼雖然是經過多次校對與邏輯限縮後的結果,但也還會有疏漏。就像過了兩三天,我今天才發現,AI 又偷偷刪掉我原本在「製」這個字的部分詞語轉換邏輯。
以上是我個人的一點淺見,希望能為這個專案的優化提供一些參考,歡迎大家一起討論研究。謝謝!
var pp = t.charAt(i - 2) || " ",
p = t.charAt(i - 1) || " ",
n = t.charAt(i + 1) || " ",
n2 = t.charAt(i + 2) || " ";
return (
// 第一層:攔截為「發」(行為/動作/技術)
p === "生" && "不代债券博卡工币录料津考药补讲证诊费邮酬帖件聘粮".indexOf(n) !== -1 ||
p === "乱" && (
"脾疯怒愁财货票奖薪电邮信布表".indexOf(n) !== -1 ||
(n === "色" && n2 === "情") ||
(n === "文" && n2 === "章") ||
"贴".indexOf(n) !== -1
) ||
(n === "卷" && "子宗".indexOf(n2) !== -1) ||
(n === "色" && "幕板影显示器".indexOf(p) !== -1) ||
(
p === "额" &&
"足满金全总差配税员份定限小大超增减名等缺補".indexOf(pp) !== -1 &&
(m.indexOf(n) !== -1 || "工补证料券币代债不".indexOf(n) !== -1)
)
) ? "發" : (
// 第二層:攔截為「髮」(生理/配件)
(p === "生" && "贼寇花".indexOf(pp) === -1) ||
p === "额" ||
"卷乱修扎插整洁翦松柔鬐鬋髶髹髺髽髾鬃鬄髦".indexOf(p) !== -1 ||
"卡冠缏髲鬄鬈绺色卷".indexOf(n) !== -1
) ? "髮" : "發"; // 第三層:其餘情況回歸預設值「發」
},