基於 Unicode General_Category 值所建構的特殊字元移除替代方案,會移除標準化的 P 標點與 S 符號字碼點,並提供精確的移除字碼點計數,而不是從字型的外觀來猜測。手動維護的 ASCII 清單與臨時拼湊的規則式 (regex) 模式的標準替代方案,是一個直接套用 Unicode 屬性跳脫 (property escapes) 的工具,因此其行為可依據已發佈的 Unicode 資料進行稽核,而非依賴某人所挑選的凍結字元清單。基於瀏覽器的處理方式代表貼上的文字永遠不會上傳到伺服器,而精確的清理結果加上被移除字碼點的計數會顯示在同一個頁面中,讓您能驗證實際的變更內容。兩種模式——廣泛 (P 加 S) 與僅符號 (S)——為跨拉丁與非拉丁書寫系統的貨幣符號、連接號、箭號、表情符號 (emoji) 與標點提供可預測的行為,且全都衍生自同一份標準文件。這個方法以「依據 Unicode 本身對各字碼點的分類定義」取代了一份「看起來很特殊」的字元查核表,這是純文字所能擁有最接近客觀規則的定義。

這種區別至關重要,因為「特殊字元」這個詞彙是非正式的。不同的產品在為功能貼上同一個標籤時,指的可能是不同的意思,這正是為什麼搜尋替代方案的讀者通常心中已有一種方法,只是想要一個更可靠的替代品。

special characters remover alternative
基於 Unicode 建構的特殊字元移除替代方案

「特殊字元」在各工具中的意義

這個說法很模糊。在某個說明中心,它可能代表任何非字母或數字的字元。在另一個說明中心,它可能代表標點符號,而表情符號則另外處理。在第三個說明中心,它可能涵蓋貨幣符號但保留數學運算子。缺乏共享定義,正是為什麼這麼多線上工具感覺可以互換,卻在相同的輸入字串上行為不一致的實際原因。

Unicode 透過 General_Category 屬性解決了這個問題。每個已指派的字碼點都恰好屬於一個頂層分類,例如字母 (Letter, L)、數字 (Number, N)、標點 (Punctuation, P)、符號 (Symbol, S) 或分隔符 (Separator, Z),而其中大多數還會進一步細分子分類。任何以 P 開頭的都正式屬於標點;任何以 S 開頭的都正式屬於符號。依據這兩個前綴進行篩選的工具,是遵循一套已發佈的分類法,而不是從某人曾經打過一次卻忘記保留的清單中挑選字元。

對於正在比較替代方案的使用者來說,結論很直接:廣泛模式的結果與僅符號模式的結果都可從標準預測,而非取決於工具的開發者。Unicode General Category Values 參考資料列出了每個字母底下的所有字碼點,而由屬性跳脫驅動的工具會比對屬於 P 或 S 的那些字碼點。

多數人拿來比較的方法

來到這個頁面的讀者,通常已經在使用下列其中一種方法。在介紹基於 Unicode 的替代方案之前,每一種都值得指出其權衡取捨。

方法適用場景主要限制
手動維護的 ASCII 清單舊式管線、範圍狹窄的領域會漏掉非 ASCII 符號、貨幣符號、表情符號與 CJK 標點
規則式 (regex) 樣式程式設計師、臨時腳本容易比對過少或過多;涵蓋範圍取決於作者的類別選擇
命令列的 sed 或 awkLinux 與 macOS 單行指令、批次檔需要 shell 存取權;行為會因地區設定與規則式方言而異
編輯器的尋找與取代對話方塊一次性的人工編輯需逐字點擊;無法驗證移除數量
基於 Unicode 類別的工具對貼上文字進行廣泛清理僅限瀏覽器使用;並非資安消毒工具

這些方法本身都沒有錯。主張使用替代方案的論點在於您想要的是哪些權衡取捨。規則式在懂字元類別的人手中可以很精確,但事後通常難以稽核——閱讀結果的人必須相信那個樣式是對的。ASCII 清單可稽核,但對 Unicode 的大部分內容視而不見。基於類別的替代方案則介於兩者之間:規則公開、比對精確,且計數會顯示在同一個檢視畫面中。

特殊字元移除替代方案的運作方式

特殊字元移除工具經過驗證的操作流程包含三個明確步驟,每一步都在介面中可見。

  1. 將要清理的文字貼到輸入框中。
  2. 選擇 Unicode 符號與標點 (廣泛,P 加 S) 或僅符號 (S)。
  3. 移除字元並驗證精確的輸出結果與被移除字碼點的計數。

舉例來說,字串 "Hi, $5!" 在僅符號模式下會變成 "Hi, 5!",因為美元符號是貨幣符號 (S),而逗號與驚嘆號則是標點 (P)。切換到廣泛模式則會產生 "Hi 5"——逗號、美元符號與驚嘆號都被移除,因為三者都符合其標準化分類。原本已經存在於 "Hi," 與 "$5!" 之間的空格會保留下來,因為這個工具不會插入替代字元。

被比對到的字碼點會被精確刪除。不會插入替代字元,不會在原本以標點分隔的字詞之間額外加入空格,且既有的空白——空格、Tab、換行——都會原封不動。最後這一點對於純文字的縮排程式碼或格式化段落清理很重要:已經存在的結構不會被正規化或修剪。

此工具完全在瀏覽器中運作,因此輸入內容絕不會離開此頁面。空白的輸入會被拒絕,且輸入上限為一百萬個 UTF-16 字碼單位 (UTF-16 code units)。編輯輸入內容或切換模式會立即清除舊的結果,因此您不會不小心複製到一份已經與目前設定不再相符的過期輸出。比對使用 JavaScript 的 Unicode 屬性跳脫加上 Unicode 旗標,如 ECMAScript Unicode 屬性跳脫 規格中所定義,因此引擎本身將 P 與 S 視為分類,而非逐一列舉字元。

Unicode 基礎的替代方案能抓到而其他方法漏掉的內容

一份由人手維護的「特殊字元」清單,通常只是某個時間點在某個 QWERTY 鍵盤上看得到的快照。而 Unicode 類別篩選器則繼承了該標準的完整範圍。

貨幣符號 ($, €, ¥, £, ₹, ₽, ¢ 等等)、數學運算子 (∑, √, ≤, ∞)、箭號 (→, ⇒, ↔)、版權與商標符號 (©, ®, ™)、許多表情符號,以及來自非拉丁書寫系統的標點,例如全形 CJK 標點 (、。・「」),全都歸類在 P 或 S 之下,並以相同的條件被比對到。連接標點的情況值得特別說明:底線在英文的直覺認知中不算標點,但 Unicode 將其歸類為 Connector_Punctuation (Pc),因此在廣泛模式下會被納入,並顯示在被移除的計數中。

同樣重要的是這個篩選器不會動到哪些內容。以基底字母加上組合標記 (combining mark) 表示的帶有附加符號的字母,由於該組合標記屬於 Mark (M) 類別而非 P 或 S,因此會被保留。小數位數字會保留。空白——包括非斷行空格 (non-breaking spaces) 與 Separator 類別下的行分隔符——也會保留。比對是作用在 Unicode 字碼點上,因此一個表情符號若以單一輔助平面字碼點表示,即使 JavaScript 內部以代理對 (surrogate pair) 儲存,也只會計算一次。多字碼點的表情符號序列中可能包含多個符號字碼點,並與接合符與變體選擇符並列;符合條件的符號會被移除,而不符合的格式字碼點則可能保留,因此這個工具並非完整的表情符號序列消毒工具。

替代方案的極限

字元篩選器並非消毒工具。將其作為 SQL 參數、HTML 屬性、shell 命令、URL 元件、檔名、使用者名稱或身分驗證資料的唯一防護並不安全,因為什麼字元被允許是由目的端的語法 (grammar) 決定,而篩選器無法得知該語法。安全的驗證需要由伺服器強制執行、針對目的端量身打造的允許清單 (allowlist)。

移除的結果也可能以重要的方式改變意義。移除貨幣符號會讓價格變成一個裸露的數字。移除數學運算子會改變方程式。移除標點會合併原本分屬不同句子的詞語,這可能會破壞螢幕閱讀器的發音,並改變文字朗讀出來的方式。請將清理後的文字視為草稿,在發佈或貼入下游系統之前加以檢視。

若是反向的工作流程——挑選要插入的確切符號而非刪除它們——策展過的特殊字元大量複製貼上參考資料讓您能依名稱提取個別字碼點。當問題出在多餘的空白而非符號時,空白移除工具會在明確的模式設定下處理空格、Tab 與空行,而不會更動字母或數字,這使得它在符號移除後暴露出額外空隙、而您也想一併清理時,成為一個有用的後續步驟。