若要在 IntelliJ IDEA 中將專案的編碼變更為 UTF-8,請依序開啟 File、Settings、Editor、File Encodings,將 Global encoding、Project encoding 以及 Default encoding for properties files 全部設為 UTF-8,接著在每個既有的原始檔上執行 UTF-8 Converter,以確認磁碟上的位元組能以有效的 UTF-8 解碼——IntelliJ 雖然控制了檔案的開啟、儲存和編譯方式,但無法追溯修復那些由舊版 Windows 工具、設定錯誤的資料匯出,或會寫入 Windows-1252 或 UTF-16 的舊版編輯器所產生的位元組。IntelliJ 的編碼設定分散在三個巢狀位置中,而且由於它們構成的是磁碟上位元組流之上的呈現層,而不是轉碼器本身,因此僅僅把旋鈕切到 UTF-8 是必要條件,卻不是充分條件。當既有檔案在位元組層級上其實並非真正的 UTF-8 時,IDE 會悄悄地以替代字元取代、拒絕編譯,或將損壞的狀態更深地推入版本控管中——這也是開發人員搜尋如何在 IntelliJ 中變更 UTF-8,卻在重新啟動並完整建構後,檔案看起來仍然錯誤的最常見原因。

how to change utf 8 in intellij
how to change utf 8 in intellij

IntelliJ 編碼設定 vs 磁碟上的位元組

IntelliJ 對每個檔案會讀取兩次編碼:一次在編輯器顯示它時,另一次在它被編譯、複製或儲存時。Global Encoding 會影響機器上所有新專案;Project Encoding 會為目前的目錄樹覆寫全域設定;而位於 File Encodings 對話框底部的個別檔案編碼覆寫,會為單一原始檔強制指定特定標籤。這些設定都不會轉換位元組;它們只會告訴標準的 WHATWG 解碼器,應該把哪個標籤傳給 IntelliJ 內部使用的 TextDecoder。若標籤與實際寫入的位元組不符,IntelliJ 要不就是顯示替換用的菱形符號、無法通過某個建構步驟,要不就是會在編輯器右下角對該檔案標示警告。這正是為什麼在排解即使變更設定後仍持續存在的亂碼或建構錯誤時,使用基於標準的轉換器進行驗證是工作流程的一部分,而非可省略的步驟。

本文所述的 File、Settings 路徑適用於 IntelliJ IDEA 2023 及更新版本;在 macOS 上則是透過 IntelliJ IDEA、Preferences 進入同一個對話框。較舊的版本(例如 14.x)使用的標籤完全相同,僅導覽方式略有不同,而更早之前的版本則會顯示一個舊式的 Other Settings、Default Settings 項目,讓系統管理員可以預先為機器上每個新開啟的工作區設定 UTF-8。

在 IntelliJ IDEA 中全面設定 UTF-8

本逐步說明涵蓋了「如何在 IntelliJ 中變更 UTF-8」這個查詢最常見的詮釋——也就是讓每個專案、每個檔案以及每個 properties 資源都預設為 UTF-8,而不針對個別來源特別處理。

  1. 在 Windows 或 Linux 上開啟 File、Settings,或在 macOS 上開啟 IntelliJ IDEA、Preferences;在所有平台上,開啟後的對話框都標示為 Settings。
  2. 在左側的樹狀結構中,展開 Editor、File Encodings。
  3. 將 Global Encoding 變更為 UTF-8。
  4. 將 Project Encoding 變更為 UTF-8。
  5. 將 Default encoding for properties files 變更為 UTF-8;這項設定特別會影響 .properties 語系檔,且 IntelliJ 在此值與 UTF-8 不一致時會發出警告。
  6. 除非專案已知依賴 Transparent native-to-ascii conversion,否則請將其保持為未勾選;現代程式碼基底應將其預設為關閉。
  7. 點擊 Apply,然後再按 OK;重新開啟任何已經開啟的專案,讓 IntelliJ 重新讀取編碼對應表。
  8. 若任何開啟檔案的右下角仍顯示編碼為 System default 或 UTF-8 with BOM,請手動切換該檔案,或依照下一節所述的方式進行轉換。
  9. 若要為整個團隊設定相同的版本,請編輯專案根目錄中的 .idea/encodings.xml,並確保每個 CHARSET 屬性都是 UTF-8;提交該檔案,讓每位貢獻者都採用相同的預設值。

每個編輯器視窗右下角的編碼狀態列,是該變更已對當前焦點檔案生效的可見確認,同時它也是唯一能證明 IDE 已不再將該原始檔視為 System default 的 UI 元素。

將標籤錯誤的原始檔轉換並驗證為 UTF-8

當某個檔案早於本次 IDE 設定變更、從外部的舊版儲存庫簽出,或由預設為 Windows-1252 的 Windows 工具所產生時,IDE 本身無法修復它,您需要使用外部的稽核工具。UTF-8 Converter 會針對 IntelliJ 專案實際會遇到的四種編碼,套用採用嚴格錯誤處理模式的 WHATWG 解碼器,接著將結果重新編碼成可下載、不含 BOM 的檔案,而且過程中不會上傳原始位元組。

  1. 根據產生該檔案的應用程式或可靠的後設資料來判斷其來源編碼——不要依賴檔案表面的外觀,因為同一組位元組序列在多個舊編碼下都可能是有效的,卻對應到不同的字元。
  2. 開啟轉換器,從磁碟中選擇檔案;大小不超過 10 MB 的檔案會直接讀入記憶體緩衝區中處理。
  3. 在選擇器中確認所選的來源編碼——UTF-8、UTF-16LE、UTF-16BE 或 Windows-1252。
  4. 點擊 Convert;預覽區域會解碼位元組、顯示渲染後的字元,並回報來源與輸出的位元組數。
  5. 若來源在嚴格驗證下進行解碼,無效的接續位元組、截斷的序列、禁止的編碼、未配對的代理對以及其他畸形情形會導致明確的失敗,而不是產生替代字元。
  6. 在預覽區域中檢查具代表性的姓名、標點符號、貨幣符號以及非 ASCII 的行;在下載之前,通常就能在此看出明顯錯誤的選擇。
  7. 下載檔案;產生的檔名會加上 -utf8 後綴,且位元組在輸出時不含 BOM,即使來源檔案中包含 BOM。
  8. 將轉換後的檔案放入 IntelliJ 專案目錄樹中,重新建構並驗證無誤後再刪除原始檔;轉換器不會修改換行格式,除非那是解碼與 UTF-8 編碼過程中所必然產生的結果。

來源與輸出之間的位元組數不同是預期中的現象,因為 UTF-8 對每個字元所使用的位元組數與 Windows-1252 或 UTF-16 不同;對於舊版來源檔案來說,位元組數相同反而才值得懷疑。大於 10 MB 的檔案應使用串流式的轉換工具來處理,因為瀏覽器的記憶體緩衝區是本工具的運作上限。

在 IntelliJ 中變更 UTF-8 時的常見陷阱

即使設定正確,開發人員在嘗試於 IntelliJ 中變更 UTF-8,卻發現字串仍然顯示為亂碼、編譯失敗,或語系檔被標示為編碼錯誤的警告時,仍會反覆遇到四個常見的問題。

properties 檔與 Java 原始檔中的 UTF-8 BOM

IntelliJ 在 BOM 存在時能夠識別 UTF-8,但在 .properties 檔案中或 Java 原始檔開頭的 BOM,會導致其他工具與 shell 腳本誤讀第一行。轉換器的 UTF-8 模式會透過基於標準的解碼器消耗掉 BOM,編碼器在下載的檔案中則不會額外加入 BOM,這正符合大多數建置管線的預期。

被標示為 ISO-8859-1 的 Windows-1252

Windows-1252 是常見的西方舊版字碼頁,常被誤標為 ISO-8859-1;其中 0x80 到 0x9F 的位元組涵蓋了可列印的標點與符號,例如歐元符號與花括號引號,而非控制字元。Windows-1252 中的歐元符號位元組 0x80 在轉換後會變成三個 UTF-8 位元組 E2 82 AC,因此一個在舊編碼下看似四個位元組長的檔案,在匯出為 UTF-8 後會變長。

UTF-16 位元組順序混淆

UTF-16LE 與 UTF-16BE 的差異僅在於位元組順序;若端序顛倒,檔案中的字母將變得毫無意義,即使成對的位元組本身仍可讀取。轉換器會將相符的 BOM 視為權威依據,並在輸出為 UTF-8 之前先將 UTF-16 代理對的兩半配對起來,如此一來,像表情符號這類輔助平面字元會以單一 Unicode 純量值的形式保留,而不會變成兩個替換用的菱形符號。

單一檔案中混合多種編碼

若檔案中同時包含 Windows-1252 位元組與 UTF-8 位元組(因為不同區段是由兩套編輯器分別儲存的),單一解碼器無法可靠地修復。轉換器在所選標籤下可能會解碼成功但損壞另一個區段,或者在嚴格驗證下直接失敗;無論是哪種情況,在進行任何進一步的編碼處理之前,都必須先將該檔案切割開來。

IntelliJ 檔案編碼參考

設定範圍對 IntelliJ 的影響
Global Encoding整個 IDE,所有新專案此機器上每個新建立專案的預設值
Project Encoding目前專案為作用中的專案目錄樹覆寫全域值
Default encoding for properties files僅限 .properties 資源避免非 Latin-1 讀取錯誤與 BOM 警告
Transparent native-to-ascii conversion內含 Unicode 的 Java 原始檔將非 ASCII 位元組以跳脫形式寫入原始碼;除非必要,否則請保持關閉
個別檔案編碼覆寫單一檔案強制使用所選標籤,而不論繼承關係為何

此工具所產生的轉換結果是可稽核的,因為編碼器是固定的、來源標籤是明確的,而且檔案從不離開瀏覽器,這正適合那些無法接受 IntelliJ 默默變更標籤的合規敏感型工作流程。

UTF-8 Converter 的來源編碼行為

所選的來源編碼解碼器行為下載的 UTF-8 輸出
UTF-8 (no BOM)以嚴格錯誤處理模式進行驗證不含 BOM 的 UTF-8 位元組
UTF-8 with BOM消耗開頭的 BOM不含 BOM 的 UTF-8 位元組
UTF-16LE以小端序解碼,合併代理對不含 BOM 的 UTF-8 位元組
UTF-16BE以大端序解碼,合併代理對不含 BOM 的 UTF-8 位元組
Windows-1252將 0x80 至 0x9F 對應至可列印符號不含 BOM 的 UTF-8 位元組

這兩個表格所描述的數值是由 IntelliJ 設定對話框與轉換器規格所定義,而非計算得出的結果,因此對於將自身專案與所記載行為進行比對的讀者來說依然有效。解碼器的標籤遵循 WHATWG Encoding Standard,使得 IntelliJ 與轉換器能與工作站上任何符合標準的編輯器保持一致。

延伸閱讀:UTF-8 Decode:將十六進位、十進位與二進位位元組解碼為文字

延伸閱讀:當檔案顯示損壞時,如何在 Notepad 中變更 UTF-8