會探討這一篇,純粹只是有一天發現:
台灣人寫的很多簡體字,都是「台式簡體字」!不是大陸簡體字!

變體字的起源,手寫異體字

台灣有台式國語、台式英語(Desktop???)
台式泡菜、台式珍奶、還有台視新聞(…發神經,別理我)
以及各式台男台女之外

對,當然也有台式簡體字

繁體 vs 台式簡寫 vs 大陸標準
ex: 個、亇、个
ex: 點、奌、点
ex: 發、発、发

比較多是 快寫產生的書寫異體:俗字、俗體字(民間流行使用但未經官方標準化的字形)
或古文字或異體字的沿用、或者日本漢字流傳
久而久之,變成地方流行起來的,約定成俗的一個「區域性文字」
就是變體字的起源

相同的字,不同的編碼?

繁體、簡體、韓語、日語、俗寫...各種中國字的撰寫方式
在電腦編碼上又是一個大坑(電腦的文字地獄)

不過,若只是要在電腦上「呈現出文字」
這些都還只是小Case,真正的文字地獄如下!

在臺灣、香港、澳門、新加坡、馬來西亞等
這些仍在使用繁體字、漢字的地區
有極少數中文國字長的一模一樣(或者說相似),卻在Unicode有不同的編碼

明明字完全相同,在特定情形下,用Ctrl+F卻搜尋不到…
還需要做Unicode等價性(Unicode Normalization)

純HTML本身無法進行正規化,因為HTML只是「標記語言」
必須靠著前端JS或者後端程式處理編碼形式

舉個例子:⼈、人
左右兩個「人」其實是不同的字

什麼?你不相信
你說你在這個頁面上,按 Ctrl+F 兩個都可以搜尋的到?!

對,那是因為Chrome、Edge、Safari等瀏覽器幫我們做了模糊比對
如果使用IDE(Sublime、VSCode、Jetbrains…等等)會發現是搜尋不到的
因為這些撰寫程式碼的工具,多數會精準比對

但是,如果將拿這兩個字反白,右鍵 => 搜尋Google結果
會發現兩者搜尋出來的結果大相逕庭

對,就是Google搜到「不同字」去了
那是因為,兩個「人」底層的編碼本身不同
⼈(U+2F08)、人(U+4EBA)
左邊是「部首字」,右邊則是日常用字

對,「部首字」跟「日常用字」的編碼完全不同
為什麼要區分、獨立出部首字?
因為部首本身並非對應漢字
有些地方很龜毛,需要明確標示「這是部首,不是用字」
康熙字典等傳統字書需要數位化,部首獨立編碼更方便整理。詳見康熙部首

比對工具網址:http://www.mytju.com/classcode/tools/encode_utf8.asp

所謂「U+2F08、U+4EBA」就是Unicode的16進制,末四位數字就是上圖紅框處

對了,在Windows上的話
注音輸入法的話輸入 「`u2605(空白鍵)」就會出現"★"
所以輸入「`u2f08(空白鍵)」就會出現"⼈"
用注音符號直輸,稱作「Unicode輸入法」

舉個例子

神(U+FA19)、神(U+795E)
左邊是日文漢字、右邊是中文字
但是這種字在Wordpress或者大多文字編輯器中,會自動轉換成「神」
因為做了相容性正規化
如果要保留日文漢字,可以在複製到IDE中貼上

兼容字 vs 正字 vs 拆分字
還有Emoji😀、符號方塊✅等字元
就能知道電腦在做相容性、多國語系、字形字體上,有多麼痛苦了吧!

字體家族 (Font family)

順帶一提,其實同一個Emoji😀表情符號在
不同手機、不同平台,甚至是不同年份的版本型號
笑臉呈現出來的圖案可能都不同,因為視作是不同的字體家族 (Font family)

所以哪一天『你看到的是 😀,我看到的可能是 😊,他看到的可能是 😐』
在極端的情況下,這件事情是有可能發生的

不僅字體家族五花八門、文字效果

還有字體的粗度(細體字、粗體字)、寬度(影響字的間隔)
大多數字體的A-Z a-z 0-9 寬度不一定相同
有些講究眼球視覺、螢幕排版的軟體工程師,就會使用等寬字體MonoFont(monospaced typefaces) ex: consolas、liga sans

涉及筆畫呈現、字型渲染、字體設計
這一部分再追根究柢,就會變成「螢幕像素點學問」了!
可玩看看「FontForge字型編輯器」,打造一套屬於自己的字體

文字的方向性

除了呈現出字型、能夠搜尋之外,文字還有分方向喔!

噢,此處不是指這種直式、橫式的書寫方式
因為這並非由Unicode 碼點層(字符本身)控管
而是交由CSS或者排版層的控制,做文字呈現樣式(writing mode)

以上都屬於CSS可控制的方向語法

Unicode控制字符:LTR、RTL、BOM

然而,此處指的文字方向(由Unicode 碼點層管理的)為
書寫方向屬性(Bidirectional Class):左到右、右到左

LTR(Left to Right)左到右語言:
英文、中文、日文、德文、俄文…等等

RTL(Right to Left)右到左語言:
阿拉伯文、希伯來文(以色列的語言)…等等

然而面臨LTR、RTL「混用」的時候,為了避免順序錯亂,就需要以下控制符號:

名稱碼點縮寫用途說明
左到右嵌入(Left-to-Right Embedding)U+202ALRE讓後續區塊強制 LTR 顯示
右到左嵌入(Right-to-Left Embedding)U+202BRLE讓後續區塊強制 RTL 顯示
左到右覆蓋(Override)U+202DLRO讓所有文字按 LTR 解釋
右到左覆蓋(Override)U+202ERLO強制從右邊開始排整段
嵌入結束符(Pop Directional Formatting)U+202CPDF結束前面開啟的方向嵌入
左到右標記(Mark)U+200ELRM插入一個不可見但具有 LTR 方向的小空格
右到左標記(Mark)U+200FRLM插入 RTL 空格
雙向隔離開始/結束(FSI/PDI)U+2068/U+2069FSI/PDIHTML5 用來解決嵌入段落中混亂的情境

這些方向控制字元有些是「看不見」但能「感受到」(排版異常、游標亂跳、文字順序怪異)
例如可以玩玩看:

RLO/PDF(U+202E/U+202C):
複製這行文字 => 在這段文字後面打的字會反過來:‮123
複製這行文字 => 在這段文字後面打的字會反過來:‮123‬結束反轉

LRM/RLM(U+200E/U+200F):
複製這行文字 => 文字游標‎移動時會發現多一個‏空白

FSI/PDI(U+2068/U+2069):
複製這行文字 => 文字游標⁨移動時會發現多一個⁩空白

(在Jetbrians IDE上呈現的樣子)

RLO其實是資安攻擊技巧
你只要複製此行:evil‮fdp.exe
修改Windows的一個附檔名,便能製造以下的效果
明明本質上仍是.exe檔案,卻「看」起來像是.pdf

BOM(Byte Order Mark,位元順序標記)

BOM (byte-order mark) 是用來標示Unicode的位元組順序
通常會出現在文件或檔案的第一個字元,以告訴你接下來編碼是什麼、解讀的方向
標記「位元序是大端/小端」

Big Endian: 大端序(大尾序),重要的數寫(高位)寫在前(記憶體位址低位)
Little Endian: 小端序(小尾序),重要的數寫(高位)寫在後(記憶體位址高位)

編碼類型BOM Bytes(16進位)說明
UTF-8EF BB BF可選
UTF-8 只有一個單位,不存在位元組順序問題
UTF-16 BEFE FF大端序
UTF-16 LEFF FE小端序
UTF-32 BE00 00 FE FF大端序
UTF-32 LEFF FE 00 00小端序

BOM與LTR、RTL問題本質上相同,都涉及到判讀的左右方向
但是處理的層級不同
前者是「位元組序(byte order)」,後者是「文字顯示方向(glyph flow)」

萬國碼感知(Unicode-aware)做的事情包山包海
包含了:特殊控制碼、方向控制、正規化合字
夠令人頭疼了吧!

UTF-8、UTF-16、UTF-32

編碼形式每個字元所用位元組數說明
UTF-81~4 bytes英文字為 1 byte
中文字多為 3 bytes
最省空間,廣泛使用
UTF-162 or 4 bytes多數字元用 2 byte
少數補充字元用 4 byte
UTF-324 bytes每個字元 4 byte,格式簡單粗暴,但最浪費空間

UTF-8 編碼範圍

UTF8(Unicode 範圍)位元組數說明
U+0000 ~ U+007F1 byte基本 ASCII(英文、數字)
U+0080 ~ U+07FF2 bytes拉丁文、希臘文
U+0800 ~ U+FFFF3 bytes中文、日文、韓文、常用符號
U+10000 ~ U+10FFFF4 bytesemoji、冷僻漢字、歷史字母

之前還遇過一個專案裡面,程式碼註解區域非常多的BS控制字元
原來是倒退鍵Backspace 控制字元 (U+0008),
在VSCode內建不會顯示、肉眼上完全看不出來(用Jetbrains IDE會顯示)
只是,這個字符在多數情況下是打不出來的(控制字元通常不會顯示!)

因為按「退格鍵」時不會插入 U+0008,而是刪除字元
會發生問題的原因在於,直接從Word或PDF文件上複製文字時,保留了控制字元

在瀏覽器或IDE直接輸入BS(U+0008)字元,是不會顯示出來、也不會有倒退效果的
但如果在終端機(Terminal)、CMD上試試看,可以成功倒退!

字元名稱Unicode常見問題
\x00NULU+0000某些 JSON 解析器會直接炸掉
\x08BACKSPACEU+0008干擾搜尋、看不見、比對錯
\x0BVERTICAL TABU+000B讓部分編輯器排版錯亂
\x1BESCAPEU+001B常殘留於終端 ANSI 控制序列中

搜尋正規化(Unicode normalization)

搜尋時的正規化還分成以下四種:
NFC、NFD、NFKC、NFKD

這些的「個別代號」是:
C:Composition(合成)
D:Decomposition(分解)
K:Compatibility(兼容)

所謂 C「合成」就是
把可以組合的字元合併成一個預組合字元(單一碼位)
ex: e (U+0065) + ́ (U+0301) → é (U+00E9)
ex: D + ̇ (dot above) → (U+1E0A)

所謂 D「分解」就是
是把一個預組合字元拆成基本字元 + 裝飾符(多個碼位)
ex: é (U+00E9) → e (U+0065) + ́ (U+0301)
ex: (U+1E0A) → D (U+0044) + ̇ (U+0307)

所謂 K「兼容」就是
只處裡「外觀不同但意思完全一樣」的字元:
ex: 「①」可以當作「1」
ex: 「㎏」可以當作「kg」
ex: 「𝒜𝒷𝒸」,可以當作「 Abc」
ex: 「Ⅳ」,可以當作「IV」
ex: 「ABC123」可以當作「ABC123」

但是
不會讓「IV」變成「4」,因為IV可能代表別的意思,不一定是數字4
不會讓「é」變成「e」,因為é有重音
不會讓「ñ」變成「n」,因為ñ有鼻音
(但我心裡吐槽,這種做法永遠存在「模糊邊界」,因為是人為決定的語意判斷)

C/D「合成/分解」就是
不論Input、不管輸入的字串為何,只要發現能合成的就合成/能拆的就拆

NFC:合併字元,保留語意
NFD:拆開字元,保留語意
NFKC:合併字元,並簡化格式(兼容語意)
NFKD:拆開字元,並簡化格式(兼容語意)

ex: 如果有 ㄅ̄𝟙é ℌ ② 兩筆資料,以下是四種不同的處理結果:

模式結果
(注音符號)
結果
(國際字元)
做了什麼?適合用途
NFCㄅ̄𝟙é ℌ ②保留字元結構
保留樣式
(最高保真)
儲存、顯示
保留樣式
NFDㄅ + ˉ + 𝟙e + ´ + ℌ + ②拆開字元結構
保留樣式
(保留花俏)
文字分析
拼音處理
NFKCㄅ̄1é H 2保留字元結構
簡化樣式
(去掉花俏)
比對前處理
輸入正規化
NFKDㄅ + ˉ + 1e + ´ + H + 2拆開字元結構
簡化樣式
(最乾淨)
搜尋引擎
資料比對
轉純文字化

模糊搜尋的種類(Fuzzy Search, Semantic Matching)

Café、Cafe、cafe 三者明明是不同的字
但是在瀏覽器內搜尋”Cafe”,三者都能夠尋找的到
這是因為瀏覽器使用了模糊搜尋

為了回答「模糊搜尋」到底可以分成哪幾種?這類問題
我整理了至今為止提出的疑惑,最終分類成這六大類型

大類型說明子分類/代表例子
A. 字形與格式變化
(外觀模糊)
同符號不同樣式
1. 字母大小寫
2. 全形/半形
3. 風格字符、符號樣式
1. Apple vs apple、Δ vs δ
2. ABC vs ABC
3. vs H vs 𝕳、 vs 1 vs 𝟙
B. 語音與書寫變體
(語音書寫模糊)
同音不同字體系
1. 同音異字
2. 注音簡寫、羅馬拼音
3. 簡體/繁體/漢字
4. 片假/平假
1. Café vs Cafe
2. ㄅ̄ → ㄅ、ㄅㄨˋ→ bu4、zhong guo中國
3. vs vs 、干 vs 幹、神 vs 神
4. vs
C. 編碼與文字標準差異(技術層模糊)同樣語意但使用不同Unicode編碼
1. Unicode 表示不同、組合字與合字
2. 異體字(獨立的部首字)
1. é vs e + ´Å vs A + °
2. ⼈ vs 人
D. 語形與語法變化
(語法模糊)
語法層級的形式差異
1. 單複數
2. 時態
3. 詞性變化
4. 變格
5. 語序
1. car vs cars、mouse vs mice
2. run vs ran、eat vs ate
3. beauty vs beautiful、decision vs decide
4. they vs them
5. 我愛你 vs 你我愛
E. 拼寫與輸入誤差
(人為錯誤模糊)
拼寫錯誤
拼音錯字
鍵盤誤觸
gooogle vs google
ariplane vs airplane
zhongguo vs zhong guo
F. 語意近似
(語意模糊)
同義詞(替代詞)
語意擴展
詞組顛倒但意圖相同
car vs automobile
virus vs pathogen
University of Tokyo vs Tokyo University
USA vs United States vs US vs America

很明顯
大多數的電腦系統、瀏覽器,只支援到 A、B、C 這三類字面模糊


後面三者(D、E、F)則需要仰賴更強的語言處理系統、或者使用神經網路模型
ex: 拼寫容錯 => Levenshtein距離、Edit distance、Soundex(拼音容錯)
ex: 同義/語意模糊 => 人工同義詞詞庫(WordNet)、詞向量(Word2Vec、GloVe、FastText)
ex: 上下文語意 => BERT、GPT、文心一言 等(Transformer架構)

手機輸入法、Google搜尋都有做到 D、E 的支援,幫助打字糾錯或猜你想打什麼

而語音辨識(Speech Recognition)又是另外一篇大主題了

結尾

語言學(意義上)講究的是:語素、詞素(morpheme)
編碼層級(Unicode)探討的是:碼點(code point)
視覺實務(人眼感知)研究的是:像素字體叢集(grapheme cluster)

終極哲學問題:
到底如何定義"一個字"呢?這真的是能夠被量化定義的嗎?
我的「字」與你的「字」,看起來一樣、寫起來一樣、讀起來也一樣
但實際上,真的一樣嗎?

一旦「講出來」
語言就從內在的「感受」轉化為外在的「表演」,它已經不是原本的那個「字」了

語言不是事物本體(essence),而是事物的界面(interface)


發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *