更改檔案中文編碼導致 git diff 亂碼之完美解法
0 | 4,234 |
大家有遇到 git diff 比對文字檔,因中文編碼更改(例如 Big5 改 UTF-8)導致結果裡有一半中文變亂碼的情況嗎?我想到一個完美解法。(我自己覺得啦,不服來戰)
git diff 遇到文字檔中文編碼不同的問題之前處理過(參考:Git 實戰技巧 - 使用 git diff 比對 UTF-16/BIG5 文字檔),但定義 textconf 再用 .gitattributes 指定檔案套用編碼的做法稱不上完美,實務上有些無法處理的狀況,例如:
- 用
git diff --no-index a.txt b.txt
任意比對非 Git Repository 下的檔案,就很難用 .gitattributes 指定中文編碼 - 同一個檔案由 Big5 換成 UTF-8 (翻修古蹟常會遇到),同一檔案修改前是 Big5,修改後是 UTF-8,在 .gitattributes 指定哪一種編碼都不對
為了觀察,我做了四個檔案,big5-src.txt、big5-dst.txt、utf8-src.txt、utf8-dst.txt,-src.txt 的內容為「中文測試 1234」、-dst.txt 的內容為「中文測試 ABC」,再分別用 Big5 或 UTF-8 編碼存檔。接著用以下批次檔排列組合存成四種結果:
git diff --no-index big5-src.txt big5-dst.txt > diff-b5-b5.txt
git diff --no-index big5-src.txt utf8-dst.txt > diff-b5-u8.txt
git diff --no-index utf8-src.txt utf8-dst.txt > diff-u8-u8.txt
git diff --no-index utf8-src.txt big5-dst.txt > diff-u8-b5.txt
如圖所示,git diff ... > result.txt 時,git 將保留檔案原始內容,Big5 就存 Big5,UTF-8 就存 UTF-8 (Grabage In Garbage Out),講求原汁原味,再看讀取檔案的程式如何解讀。故左側的 Big5 對 Big5 與 UTF-8 對 UTF-8 沒什麼爭議,Notepad++ 自動識別成 Big5 及 UTF-8。但右側兩個檔案同時有 Big5 及 UTF-8,若 Notepad++ 先看到 Big5 中文,檔案會被視為 Big5 (ANSI),UTF-8 部分變亂碼;若先看到 UTF-8 中文,則 Big5 部分變亂碼。
嘗試過幾個解決方向,最後我想到一個美妙解法 - 讓 git diff 結果維持原有 Big5 與 UTF-8 並存的狀況,寫一支工具程式將其解讀成 UTF-8,但是將 Big5 部分轉換成 UTF-8,並標示 <BIG5>,用這個美化版本輔助想釐清亂碼內容的人理解。
美化效果如下:(Cmder type 預設用 Big5 編碼,故 UTF-8 部分變亂碼,美化後 Big5 與 UTF-8 都能正確顯示)
美化程式還加了簡單的亂碼偵測,只在包含 Big5 中文時標註 <BIG5>,純英文時則正常輸出。
附上 BeautifyBig5Diff.ps1 程式碼,想用的同學請自取修改使用。
param (
[Parameter(Mandatory=$true)]
[string]$diffPath
)
$sourceCode = @"
using System.IO;
using System.Text;
using System;
public class DiffBig5Convertor {
static Encoding encBig5 = Encoding.GetEncoding(950);
static Encoding encUTF8 = Encoding.UTF8;
public static string Convert(string diffPath) {
var buff = File.ReadAllBytes(diffPath);
var lineStartPos = 0;
var inDiff = false;
var sb = new StringBuilder();
for (var idx = 0; idx < buff.Length; idx++) {
if (buff[idx] == 0x0a || idx == buff.Length - 1)
{
byte[] lineBytes = new byte[idx - lineStartPos + 1];
Array.Copy(buff, lineStartPos, lineBytes, 0, lineBytes.Length);
string line = encUTF8.GetString(lineBytes);
if (inDiff) {
if (line.StartsWith("dif --git")) inDiff = false;
else if (line.Contains("�") && (line.StartsWith("-") || line.StartsWith("+")))
{
var b5Line = encBig5.GetString(lineBytes, 0, lineBytes.Length);
if (b5Line != line)
line = b5Line[0] + "<BIG5>" + b5Line.Substring(1);
}
}
else if (line.StartsWith("@@"))
inDiff = true;
sb.Append(line);
lineStartPos = idx + 1;
}
}
return sb.ToString();
}
}
"@
Add-Type -TypeDefinition $sourceCode -Language CSharp
[DiffBig5Convertor]::Convert((Resolve-Path $diffPath))
Change Chinese encoding of file always causes corruption in git diff report, this article demostrating a way to solve to issue wit a PowerShell script.
Comments
Be the first to post a comment