Text文檔編碼識別方法
在做文檔讀取的時候,時常碰到編碼格式不正確的問題,而要怎麼樣正確識別文檔的編碼格式,成了很多程序員的一塊心病,今天我就要試著治好這塊心病,這段代碼的濃縮來自上千萬文檔的數據分析所得,可靠率極其高。
應朋友要求,需要幫他做一個文章操作工具,既然想操作,就有文件的讀取和修改,本來花費幾個小時信心滿滿把程序交給朋友的時候,朋友突然來了句,很多文章打開出現亂碼的情況,我哩個去,像是晴天霹雳深深的擊在我的心窩裡,我突然想到了文件編碼問題,而這個問題,我曾經無數次的嘗試,最終都以失敗而告終,每次嘗試,只不過是減少了錯誤概率的出現,但是還不足以彌補文件編碼格式分析完全的正確,而這次,朋友又提出來編碼問題,我瞬間凌亂了。
如果不把這個問題解決,給朋友做的工具等於沒有任何作用,我TM前兩天還吃人家一頓大餐,難道還能吐出來嗎?這個搞不定,面子就丟大了,無奈之下,我詢問了朋友那裡有多少文件?得到答復:好幾千萬。瞬間我眼光放亮了,那就海量數據分析吧。
海量數據分析的時候,我使用的是一個笨方法,就是把所有文件頭數據讀取出來,比如讀取4個byte,然後將讀取的文件內容的前一百個字以(Unicode,UnicodeBigEndian,UTF8,ANSI等等)讀取出來,肉眼識別吧,比如
public class Info{
public int ch0;//第一個字符
public int ch1;//第二個字符
public int ch2;//第三個字符
public int ch3;//第四個字符
public string UnicodeStr;//前100個字
public string UnicodeBigEndianStr;//前100個字
public string UTF8Str;//前100個字
public string ANSIStr;//前100個字
}
然後使用lambda做排序,個人建議對UnicodeStr,UnicodeBigEndianStr,UTF8Str,ANSIStr這些做排序,因為可識別的字符編碼有一定的區間范圍,做排序後,可識別漢字的一定都堆在一起;
再有就是可以對 ch0,ch1,ch2,ch3,做詳細分類,看看它們之間都有什麼樣的關系,通過觀察,我也是能發現什麼的;通過歸納和總結,就得出了TEXT編碼的可識別方法,如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace 文章操作工具 { public class TextHelper { public static System.Text.Encoding GetType(string filename) { FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read); System.Text.Encoding r = GetType(fs); fs.Close(); return r; } public static System.Text.Encoding GetType(FileStream fs) { /* Unicode ------------------ 255 254 ====================== UnicodeBigEndian ------------------- 254 255 ====================== UTF8 ------------------- 34 228 34 229 34 230 34 231 34 232 34 233 239 187 ====================== ANSI ------------------- 34 176 34 177 34 179 34 180 34 182 34 185 34 191 34 194 34 196 34 198 34 201 34 202 34 205 34 206 34 208 34 209 34 210 34 211 34 213 196 167 202 213 206 228 */ BinaryReader r = new BinaryReader(fs, System.Text.Encoding.Default); byte[] ss = r.ReadBytes(3); int lef = ss[0]; int mid = ss[1]; int rig = ss[2]; r.Close(); /* 文件頭兩個字節是255 254,為Unicode編碼; 文件頭三個字節 254 255 0,為UTF-16BE編碼; 文件頭三個字節 239 187 191,為UTF-8編碼;*/ if (lef == 255 && mid == 254) { return Encoding.Unicode; } else if (lef == 254 && mid == 255 && rig == 0) { return Encoding.BigEndianUnicode; } else if (lef == 254 && mid == 255) { return Encoding.BigEndianUnicode; } else if (lef == 239 && mid == 187 && rig == 191) { return Encoding.UTF8; } else if (lef == 239 && mid == 187) { return Encoding.UTF8; } else if (lef == 196 && mid == 167 || lef == 206 && mid == 228 || lef == 202 && mid == 213) { return Encoding.Default; } else { if (lef == 34) { if (mid < 220) return Encoding.Default; else return Encoding.UTF8; } else { if (lef < 220) return Encoding.Default; else return Encoding.UTF8; } } } } }