Batch-convert file encoding
前言
在利用 Gemini CLI 幫我整理舊專案的程式時,我發現有些被 Gemini CLI 改過的檔案,裡面的中文字會變成亂碼。這才知道它目前並未支援檔案編碼的偵測,而是一律把修改過的檔案以 UTF-8 編碼來儲存,因而導致某些原先以 Big5 編碼的檔案內的中文字變成亂碼。若要手動一個個轉檔,太耗時費力了,也容易遺漏。於是,我透過 ChatGPT 的幫助產生了兩個指令腳本來解決這個問題。
目標: 批次轉換檔案的編碼,從 Big5 轉換成 UTF-8。(稍加修改之後也能用來處理其他編碼的轉換)
前提: 必須先偵測檔案的編碼是否為 Big5,是的話才能轉換成 UTF-8 編碼。不能任何檔案拿來就直接轉成 UTF-8,否則檔案裏面的中文字(或其他語言的字元)可能會變成亂碼。
此解法是問 ChatGPT 得到的。過程大致如下:
- 詢問 ChatGPT 解法,條件是要能一次大量轉換指定目錄下的所有檔案(包含子目錄)。ChatGPT 提供的幾個解法當中,有一個是 PowerShell 命令,可一次將多個檔案的編碼一律轉換成 UTF-8。
- 從 GitHub 上面找到一個開源工具 chardet 有支援偵測 Big5 編碼,而且準確率看起來是可用的(誤判率低)。
- 請 ChatGPT 修改步驟 1 生成的 PowerShell 指令,在將檔案編碼轉換成 UTF-8 之前,先調用 chardet 的編碼偵測結果來判斷檔案是否為 Big5,是的話才執行轉換。若檔案不是 Big5 編碼則略過。
接著是完整的步驟和指令腳本。
Step 1. 安裝 chardet
首先要在電腦上安裝 chardet:
pip install chardet
Step 2. 用來偵測檔案編碼的 Python 腳本
將以下 Python 程式碼儲存為 detect_encoding.py
:
# detect_encoding.py
import sys
import chardet
def detect_encoding(file_path):
with open(file_path, 'rb') as f:
raw = f.read(100000) # 讀前100KB
result = chardet.detect(raw)
print(result['encoding'])
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python detect_encoding.py <file_path>")
else:
detect_encoding(sys.argv[1])
假設將此檔案儲存於 d:/work/
目錄下。下一個步驟的 PowerShell 指令也會放在此目錄下。
Step 3. 建立 PowerShell 批次轉檔腳本
以下 PowerShell 指令會搜尋當前目錄及其所有子目錄下所有符合指定類型的檔案(*.txt
、*.cs
、*.md
),然後將編碼為 Big5 的檔案轉換成 UTF-8。
# 設定 Python 路徑與偵測編碼的 Python 腳本路徑
$pythonPath = "python" # 或指定完整路徑,如 C:\Python39\python.exe
$detectScript = "d:\work\detect_encoding.py"
# 產生 UTF-8 with BOM 編碼器
$utf8Encoding = New-Object System.Text.UTF8Encoding($true)
# 處理多個副檔名:.txt, .cs, .md
$extensions = @("*.txt", "*.cs", "*.md")
foreach ($ext in $extensions) {
Get-ChildItem -Recurse -Filter $ext | ForEach-Object {
$file = $_.FullName
try {
$detectedEncoding = & $pythonPath $detectScript $file
} catch {
Write-Host "偵測編碼失敗:$file"
return
}
if ($detectedEncoding -eq "Big5") {
Write-Host "轉換 Big5 檔案: $file"
$big5Encoding = [System.Text.Encoding]::GetEncoding("big5")
$bytes = [System.IO.File]::ReadAllBytes($file)
$text = $big5Encoding.GetString($bytes)
[System.IO.File]::WriteAllText($file, $text, $utf8Encoding)
}
else {
Write-Host "略過(非 Big5): $file (偵測為 $detectedEncoding)"
}
}
}
使用之前,請先確認:
$detectScript
變數是否指向正確路徑。$extensions
變數是否包含所有需要處理的檔案類型。
然後將指令儲存為 d:/work/big5-to-utf8.ps1
,準備在下一個步驟執行真正的轉換工作。
此指令會直接覆蓋原始檔案!如果你覺得這樣不保險,請務必先備份檔案,或自行修改指令,將轉換過的檔案存放至其他資料夾。
Step 4. 執行
執行時,先切換當前路徑至需要轉換編碼的檔案所在的目錄,然後執行上一個步驟的 PowerShell 指令。
cd d:\Projects\MyApp
d:\work\big5-to-utf8.ps1
以下截圖展示了執行結果:
從圖中可以看到,不是 Big5 編碼的檔案會略過。因此,如果在同一個目錄下重複執行這個腳本,那麼第二次執行的結果應該是全部的檔案都被略過,因為第一次執行時就已經把需要轉換的檔案都轉成 UTF-8 編碼了。
雖然我自己使用時沒有碰到問題,但無法保證在你的機器上也能 100% 沒問題。如要使用,請務必在執行批次轉換之後逐一檢查每個檔案(我是查看 git diff),並確認程式可以通過編譯和測試。
Job done! Keep learning with AI. 😊