Base100 是一種位元組到表情符號的對應方式,其中每個位元組 b 會被替換為包含碼位 U+1F3F7 加上 b 的字元,因此位元組 255 會變成 U+1F4F6,位元組 0 會變成 U+1F3F7。一個可用的 Base100 編碼器/解碼器替代方案必須遵守這個精確的公式:先將輸入字串轉成 UTF-8,編碼時把位元組值加上 U+1F3F7,解碼時則將其減去,並拒絕任何包含超出 256 個符號區段以外碼位的貼上內容。此對應方式由 Adam Niederer 的 Base100 專案所引入,之後有數個命令列分支、Go 函式庫和網頁工具都沿用了它們。在原理上切換這些工具很簡單,但實際的替代方案在處理 UTF-8 驗證、位元組限制、剪貼簿轉換,以及是在本地端執行或需要伺服器往返等方面各不相同。Base100 編碼器/解碼器 完全在瀏覽器中執行,會靜默拒絕無效的輸入,並採用嚴格的 UTF-8 解碼,因此當貼上的位元組流與原始位元組不再相符時,會直接以錯誤大聲失敗,而不是產生損壞的字串。

關鍵字詞「base100 編碼器/解碼器替代方案」通常代表一個已經了解該格式、並想以另一個更符合特定限制的實作來取代原有實作的讀者。該限制經常是隱私(不上傳到遠端伺服器)、嚴格的正確性(壞的輸入不會產生替換字元),或是便利性(不需要安裝 Rust 工具鏈)。下面的章節說明在切換前應比較什麼、如何使用 Lizely 工具作為替代方案,以及會讓外觀相同的貼上位元組流在嚴格解碼時失敗的特定陷阱。

base100 encoder / decoder alternative
Base100 編碼器/解碼器替代方案:瀏覽器切換

為什麼讀者會尋找 Base100 編碼器/解碼器替代方案

原本的 Base100 是由 Adam Niederer 以 Rust 撰寫的命令列工具,將輸入位元組流的每個位元組對應到 256 個符號表情符號區段中的唯一字元。它是規範的參考實作,任何聲稱為相容 Base100 編碼器/解碼器替代方案的工具,都必須遵循相同的位元組到符號規則。當現有設定發生下列三種情況之一時,讀者通常會搜尋替代方案。

  • 本地安裝不切實際。原本的 Rust crate 以及數個 Go 移植版本在使用前都必須先編譯或安裝。在受管理的筆電、手機或借用機器上工作的讀者,經常會想要一個直接在瀏覽器分頁中開啟的工具。
  • 隱私規定阻擋上傳。較舊的網頁版 Base100 轉換器會將文字貼到後端,再由後端回傳編碼後的位元組流。對於機密輸入而言,這種作法無法接受,因此會偏好用戶端替代方案。
  • 靜默的 UTF-8 錯誤破壞往返一致性。有些實作會將無效的位元組替換為 Unicode 替換字元 (U+FFFD) 並回報成功。這會掩蓋真正的失敗,使解碼後的文字與原始位元組流不再相符。

上述每個痛點都指向同一個架構選擇:替代方案必須在本地端轉換、嚴格驗證,且絕不能靜默改寫位元組。Lizely 工具滿足這三點。

這個 Base100 替代方案有何不同

有幾項已記錄的特性可以區分一個合規的替代方案與草率的仿製。這些特性在 Lizely 的實作中都可看到,且都符合原始 Base100 README 和 Go 參考函式庫中的規則。

  • 嚴格的位元組範圍強制執行。解碼器僅接受 U+1F3F7 到 U+1F4F6 的碼位。該區段外的空格、換行、標點、變體選擇器及表情符號都會直接被拒絕。
  • 嚴格的 UTF-8 驗證。在將符號轉回位元組之後,會依 WHATWG 編碼標準將位元組以 UTF-8 解碼。若該位元組序列並非有效的 UTF-8,工具會回傳清楚的錯誤,而不是插入替換字元。
  • 僅在本地端處理。編碼與解碼都在瀏覽器中執行。文字從不離開裝置,這消除了機密輸入一整類的合規風險。
  • 固定的位元組限制。任一方向的處理皆上限為 500,000 個位元組或符號,以避免意外貼上大量內容導致分頁凍結。
  • 無填充、檢查碼或分隔符。該對應是每個位元組對應一個符號。沒有長度標記、沒有分隔符,也沒有偵測竄改用的雜湊值,因此任何單一符號的變更都會改變對應的位元組。

如何使用 Base100 替代方案編碼文字

  1. 開啟 Base100 編碼器/解碼器,並選擇文字轉 Base100。
  2. 輸入或貼上你想要編碼的 UTF-8 文字。工具會先將字串轉成 UTF-8 位元組,因此含音調字母、CJK 字元及表情符號都會依其 UTF-8 表示展開。
  3. 執行編碼器。每個位元組 b 都會成為碼位 U+1F3F7 + b,工具會為每個位元組產生一個 Base100 符號。
  4. 複製產生的符號流。請勿加入空格、換行或變體選擇器,因為解碼器會拒絕任何不在 256 個符號範圍內的字元。
  5. 將該位元組流貼到需要編碼形式的目標中。若目標將這些符號渲染為彩色表情符號、單色字形或方框,只要碼位沒有被替換,渲染並不會改變底層的碼位,因此該位元組流仍然可以解碼。

對於一般的 ASCII 文字,符號數等於字元數。對於非 ASCII 文字,符號數通常較多,因為一個使用者感知的字元通常會佔用數個 UTF-8 位元組。因此輸出測量的是編碼後的位元組,而不是字元、單字或字位群集。

如何將符號解碼回文字

解碼就是反過來套用同一個公式。將工具切換到Base100 轉文字,貼上未經修改的符號流,並執行解碼器。每個符號都必須落在 U+1F3F7 到 U+1F4F6(含)之內。工具會從每個碼位減去 U+1F3F7 以還原位元組值,收集所有位元組後,再以 WHATWG UTF-8 解碼器重建原始文字。

若該位元組流無效,可能發生三種不同的失敗模式:

  • 超出範圍的碼位。落在 U+1F3F7 到 U+1F4F6 之外的符號會立即被拒絕,因為公式無法從中還原出有效的位元組。
  • 變體選擇器或隱藏字元。有些聊天應用程式、編輯器、鍵盤及正規化流程會在表情符號後插入變體選擇器 (U+FE0F)。該選擇器落在 Base100 範圍之外,因此在螢幕上看起來視覺相同的位元組流,在位元組層級是不同的,會導致嚴格解碼失敗。
  • 無效的 UTF-8 位元組序列。當位元組本身無法組成有效的 UTF-8 字串時,解碼器會回報嚴重錯誤,而不是用替換字元取代這些位元組。這就是 WHATWG 編碼標準 中定義的同一種嚴格 UTF-8 行為。

比較 Base100 替代方案的實作

在切換工具之前,請比較幾項已記錄的特性。下方表格摘要說明 Lizely Base100 編碼器/解碼器與原始 Rust 命令列工具,以及記載於 pkg.go.dev 的 Go 參考函式庫之間的對應情形。表格中的儲存格值反映各專案中公開記錄的行為,而非未經驗證的宣稱。

特性Lizely Base100 工具原始 Rust CLIGo 參考函式庫
轉換執行位置在瀏覽器中,不上傳在安裝 Rust 之後於本機執行在 Go 程式中於本機執行
接受的符號範圍僅限嚴格的 U+1F3F7 到 U+1F4F6僅限嚴格的 U+1F3F7 到 U+1F4F6僅限嚴格的 U+1F3F7 到 U+1F4F6
對應公式位元組 b 成為 U+1F3F7 + b位元組 b 成為 U+1F3F7 + b位元組 b 成為 U+1F3F7 + b
UTF-8 邊界處理依 WHATWG 標準進行嚴格驗證在輸入處採標準 UTF-8 邊界在輸入處採標準 UTF-8 邊界
使用前需要的設定無,在瀏覽器分頁中執行需要 Rust 工具鏈需要 Go 工具鏈
固定的大小限制每方向 500,000 個位元組或符號取決於主機機器取決於主機程式

Lizely 工具非常適合想要使用該格式、但不想安裝工具鏈也不想進行伺服器往返的讀者。Rust CLI 更適合在 shell 管線中批次處理大型檔案,因為瀏覽器分頁有固定的大小上限。Go 函式庫則是將 Base100 嵌入到另一個 Go 程式的最佳選擇。

切換工具後會破壞解碼的陷阱

從一個 Base100 實作切換到另一個通常是很順暢的,但有少數常見的錯誤會導致貼上的位元組流在嚴格解碼時失敗。

  • 加入空白字元。即使符號之間只有一個空格,也會使一個碼位超出接受範圍。解碼器會拒絕該位元組流,而不是略過該空格。
  • 變體選擇器。表情符號的渲染常常會自動附加 U+FE0F。該選擇器不屬於 Base100 的一部分,因此從彩色聊天用戶端複製貼上時,可能會注入改變位元組數的隱藏字元。
  • 字型或系統替代。某些平台在複製時會將 Base100 碼位替換為不同的表情符號。即使螢幕上的視覺外觀相似,位元組內容仍會改變。
  • 截斷。該格式沒有長度標記,因此若貼上的位元組流少了一個位元組,解碼結果可能是末端缺少一個位元組的字串;若是該截斷使非 ASCII 文字中的多位元組 UTF-8 序列不完整,則會產生無效 UTF-8 錯誤。請務必貼上完整的位元組流。
  • 編碼不相符。若目標環境僅支援 ASCII,Base100 符號可能會被完全移除。在此情況下請改用 Base64、十六進位,或其他僅限 ASCII 的編碼方式。

若想進一步了解位元組到符號公式的背景,以及非 ASCII 文字如何展開,Base100 編碼速查表 詳細說明了對應方式,而原始的 Adam Niederer Base100 儲存庫則記錄了每個合規替代方案所使用的參考公式。

一旦位元組完全一致的工作流程就緒,切換到瀏覽器版 Base100 替代方案就只是將現有步驟替換為 Lizely 工具:貼上文字、複製符號流、再貼上一次以解碼,並驗證往返結果。由於該對應是可逆的,且該工具拒絕靜默改寫位元組,凡是符合這些規則的替代方案,都能取代原本的 CLI 而不會改變最終的位元組流。