BOM 移除工具是一個基於瀏覽器的工具,會從已解碼、貼上的文字片段中,精準移除一個位於開頭的 U+FEFF 位元組順序標記,同時保留其他所有字元,包括任何位於內部、結尾或第二個開頭的 U+FEFF 出現位置。它會檢查貼上的 JavaScript 字串的第一個 UTF-16 字碼單元是否等於 U+FEFF(十六進位 FEFF),若相符,便使用精準的 slice 運算回傳移除該字碼單元後的輸入內容。實作刻意避免使用 trim、normalize、scan 或全域 replace,因此位於位置零的不必要的 BOM 會被移除,但其他所有字元都會維持原位,包括 CRLF 與 LF 行尾符號、Tab 字元、表情符號、組合記號、代理對、非拉丁文指令碼,以及任何後續出現的零寬度字元。整個處理過程完全在當前的瀏覽器分頁中執行,文字不會上傳到任何外部服務,且工具會回報是否確實移除了開頭的 BOM,或是輸入內容本來就是乾淨的。這使得它成為一種精準、可預測的選擇,適合在需要去除檔案開頭 BOM、同時避免損壞其餘內容的情境下使用。

how to remove bom from file
how to remove bom from file

為什麼開頭的 BOM 會破壞某些檔案

當 UTF-8、UTF-16 或 UTF-32 檔案被解碼為字串後,第一個字元有時會是 U+FEFF 字碼點。該字元即 Unicode 位元組順序標記,在位元組串流的開頭作為編碼簽章具有其正當用途。根據 WHATWG 編碼活標準(Encoding Living Standard),解碼器可以在任何使用者可見內容之前消耗一個 BOM,但也可以將它原封不動地傳遞給呼叫端。當解碼器將它原封不動地傳遞時,該 U+FEFF 便會成為解碼後文字的一部分,出現在位置零。

從此之後,這個隱形的 BOM 可能會干擾任何將第一個字元視為內容的處理程序:

  • JSON 解析器會拒絕任何在第一個 token 之前出現非空白字元的字串,因此會拒絕以 U+FEFF 開頭的字串。
  • 帶有 shebang 行的Shell 指令碼會執行失敗,因為前兩個位元組是 BOM,而非 "#!" 序列。
  • CSV 欄位名稱會對齊錯誤,當 BOM 被視為第一個標頭的一部分時,因為第一欄最終會被命名為 "\uFEFFid" 而非 "id"。
  • 字串比較與相等性檢查即使可見字元相符,也會回傳 false,因為第一個字碼單元不同。
  • Markdown、XML 與樣板引擎可能會將 BOM 渲染為可見的雜訊,或是使渲染輸出位移一個字元。

標準的解決方法是在檔案其餘部分被處理之前,先去除那個位於開頭的字碼單元。BOM Remover 正是為了這個解決方法而打造,且僅用於此目的,因此它不會模糊 BOM 移除與更廣泛清理作業之間的界線。

如何使用 BOM Remover 從檔案中移除 BOM

此工具適用於已經解碼的文字。您貼入其文字區域的任何內容都會被視為 JavaScript 字串,而不是原始位元組,因此開頭的 U+FEFF 必須已經以字元的形式出現在瀏覽器中的位置零。整個操作非常直覺。

  1. 在編輯器或終端機中開啟檔案,並複製其解碼後的內容。一款能正確處理檔案編碼的純文字編輯器就相當好用。若您透過會去除零寬度字元的剪貼簿進行複製,請先貼到能顯示這些字元的工具中,再重新複製。
  2. 將文字貼到 BOM Remover 的文字區域中。開頭的隱形 U+FEFF(若存在)會被納入字串的第一個字碼單元。瀏覽器不會顯示它,但 JavaScript 字串仍然以它作為開頭。
  3. 執行移除工具並讀取狀態訊息。摘要會說明是否確實移除了剛好一個開頭的 U+FEFF,或是輸入中根本未發現開頭的 U+FEFF。輸出的長度(以 UTF-16 字碼單元計算)會顯示在輸入長度旁邊。
  4. 檢視完整的輸出,包括行尾符號與任何刻意保留的後續 U+FEFF 內容。結果面板會以完全等同於複製後內容的方式呈現完整輸出,因此 CRLF 序列、Tab 字元與任何非初始位置的 U+FEFF 字元都會保持可見,供您檢查。
  5. 在本機複製結果並存回檔案。點擊複製控制項會使用精準的 slice 運算,因此放入剪貼簿的值會與可見輸出在字元上一一對應。將它貼回您的編輯器,並以相同的檔名儲存。

若狀態訊息回報未發現開頭的 U+FEFF,表示輸入並未以該字碼單元開頭,且輸出與輸入完全相同。此時沒有需要移除的內容,檔案在位置零本來就是乾淨的。

輸入格式、限制,以及狀態訊息所代表的意義

由於此工具是基於瀏覽器中的 JavaScript 字串運作,因此無法看見檔案的位元組或原始編碼。它只能看見文字區域中已解碼的字元。這樣的選擇在實際處理檔案時會帶來兩項實際影響。

首先,輸入與輸出的大小上限皆為 200,000 個 UTF-16 字碼單元。剛好達到上限的輸入會被接受;再多一個字碼單元會在處理開始前遭到拒絕。UTF-16 字碼單元不等同於位元組,以代理對編碼的補充字元會計為兩個字碼單元。輸出本身也有獨立的 200,000 字碼單元上限,而由於轉換作業最多只會移除零或一個字碼單元,因此有效的輸入在處理過程中不會變長。邊界檢查仍會作為明確的不變式加以強制執行。

其次,狀態訊息是實際發生了什麼事的唯一依據。它會區分以下三種情況:

  • 已移除一個開頭的 U+FEFF。輸入以 U+FEFF 開頭,且輸出剛好少一個字碼單元。
  • 未發現開頭的 U+FEFF。輸入並非以 U+FEFF 開頭,且輸出與輸入在字元上一模一樣。
  • 輸入超出上限。輸入或輸出會超過 200,000 個字碼單元,因此處理程序未執行。

編輯或清除輸入會立即清空先前的輸出、錯誤訊息、摘要、移除旗標、複製訊息與待處理的複製計時器。這代表超出上限的錯誤不會留下先前的舊有成功結果,過期的剪貼簿通知也無法跨越重試動作存活下來。由於剪貼簿存取是非同步的,每次複製動作都會獲得一個世代識別碼,因此延遲抵達的權限回應無法還原過期的「已複製」狀態。遭到拒絕的請求會保留完整的唯讀輸出,以供手動選取。

常見的檔案情況與工具的處理方式

此轉換作業刻意保持範圍狹窄,因此對於各類檔案內容的行為都是固定且可預測的。下表摘要了您在清理檔案時會遇到的一般情況。

輸入樣式 BOM Remover 的動作 輸出與輸入長度比較
以單一 U+FEFF 開頭 僅移除第一個字碼單元 少一個字碼單元
以兩個 U+FEFF 開頭 移除第一個;第二個成為新的第一個字碼單元 少一個字碼單元
並非以 U+FEFF 開頭 無變更,輸出與輸入相同 長度相同
空字串 無變更,輸出為空白的結果面板 長度相同 (0)
輸入僅為一個 U+FEFF 將其移除,輸出為空但仍會渲染 零(原本為 1)
U+FEFF 出現在換行之後、中段或結尾 位置零不變動,所有後續的 U+FEFF 均保留 長度相同

其中有兩種情況值得特別說明。首先,空白的輸出是有效的結果,並非失敗。一個原本僅包含 BOM 的檔案,在移除後會變成空字串,且結果面板仍會渲染,以避免將「沒有可見字元」誤判為「操作未執行」。其次,Unicode 允許非初始位置的 U+FEFF 帶有零寬度不中斷空格(zero-width no-break space)的語意,並作為內容的一部分。工具刻意保留這些位置,即便 Unicode 標準現在建議新文字使用 U+2060 WORD JOINER。移除所有出現位置會造成破壞性的結果,而實作中也未呼叫 trim、trimStart、replaceAll 或全域正規表達式。

BOM Remover 不會執行的動作

此工具的範圍限定於一項狹窄的操作,若干相關任務刻意落在範圍之外。了解它「不會」做什麼,與了解它「會」做什麼同樣重要。

  • 它不會偵測檔案編碼。文字區域看到的是已解碼的字元,而非像 EF BB BF、FE FF 或 FF FE 這類原始位元組。從貼上的字串中,無法還原原始編碼。
  • 它不會移除所有類似的 BOM 字元。每次執行僅移除一個開頭的 U+FEFF。內部、結尾與第二個開頭的 U+FEFF 字元都會保留在輸出中。
  • 它不會標準化空白、行尾符號或 Unicode 形式。CRLF 維持 CRLF,LF 維持 LF,Tab 與 NUL 不會被修改,且不會套用任何 NFC 或 NFKC 標準化。
  • 它不會修復亂碼(mojibake)或修正錯誤解碼的內容。因錯誤編碼而產生的亂碼字元不會被偵測或修正。
  • 它不會上傳或傳輸您的檔案內容。所有作業都在當前的瀏覽器分頁中進行,剪貼簿寫入也是在本機執行。

若您能控制檔案載入步驟,處理 BOM 的正確位置在解碼器。許多程式庫接受 BOM 政策旗標,讓消費者自行選擇要消耗 BOM 還是將它原封不動傳遞。當上游工具已經將不必要的開頭 U+FEFF 暴露出來,而您需要在管線的下一個步驟之前加以清理時,將內容貼入 BOM Remover 是合適的做法。在將清理後的結果複製回覆到原始檔案之前,請確認該開頭的 U+FEFF 確實是不必要的,因為同一個字元也可能是刻意的內容。

若想深入了解底層字串規則,MDN JavaScript lexical grammar 參考文件說明了來源文字的解讀方式,包括指令碼開頭處類空白字元的處理。WHATWG Encoding Living Standard 則說明了解碼器如何將 BOM 暴露給呼叫端,或將其透明地消耗,這正是本工具所處理之開頭 U+FEFF 情境的原始來源。

若您在權衡各種選項,How to Remove the UTF-8 BOM From a File in Windows 有詳細說明。

若您在權衡各種選項,How to Remove a BOM in Text Pasted From SAP 有詳細說明。