Text文檔編碼識(shí)別方法
在做文檔讀取的時(shí)候,時(shí)常碰到編碼格式不正確的問(wèn)題,而要怎么樣正確識(shí)別文檔的編碼格式,成了很多程序員的一塊心病,今天我就要試著治好這塊心病,這段代碼的濃縮來(lái)自上千萬(wàn)文檔的數(shù)據(jù)分析所得,可靠率極其高。
應(yīng)朋友要求,需要幫他做一個(gè)文章操作工具,既然想操作,就有文件的讀取和修改,本來(lái)花費(fèi)幾個(gè)小時(shí)信心滿滿把程序交給朋友的時(shí)候,朋友突然來(lái)了句,很多文章打開(kāi)出現(xiàn)亂碼的情況,我哩個(gè)去,像是晴天霹靂深深的擊在我的心窩里,我突然想到了文件編碼問(wèn)題,而這個(gè)問(wèn)題,我曾經(jīng)無(wú)數(shù)次的嘗試,最終都以失敗而告終,每次嘗試,只不過(guò)是減少了錯(cuò)誤概率的出現(xiàn),但是還不足以彌補(bǔ)文件編碼格式分析完全的正確,而這次,朋友又提出來(lái)編碼問(wèn)題,我瞬間凌亂了。
如果不把這個(gè)問(wèn)題解決,給朋友做的工具等于沒(méi)有任何作用,我TM前兩天還吃人家一頓大餐,難道還能吐出來(lái)嗎?這個(gè)搞不定,面子就丟大了,無(wú)奈之下,我詢問(wèn)了朋友那里有多少文件?得到答復(fù):好幾千萬(wàn)。瞬間我眼光放亮了,那就海量數(shù)據(jù)分析吧。
海量數(shù)據(jù)分析的時(shí)候,我使用的是一個(gè)笨方法,就是把所有文件頭數(shù)據(jù)讀取出來(lái),比如讀取4個(gè)byte,然后將讀取的文件內(nèi)容的前一百個(gè)字以(Unicode,UnicodeBigEndian,UTF8,ANSI等等)讀取出來(lái),肉眼識(shí)別吧,比如
public class Info{
public int ch0;//第一個(gè)字符
public int ch1;//第二個(gè)字符
public int ch2;//第三個(gè)字符
public int ch3;//第四個(gè)字符
public string UnicodeStr;//前100個(gè)字
public string UnicodeBigEndianStr;//前100個(gè)字
public string UTF8Str;//前100個(gè)字
public string ANSIStr;//前100個(gè)字
}
然后使用lambda做排序,個(gè)人建議對(duì)UnicodeStr,UnicodeBigEndianStr,UTF8Str,ANSIStr這些做排序,因?yàn)榭勺R(shí)別的字符編碼有一定的區(qū)間范圍,做排序后,可識(shí)別漢字的一定都堆在一起;
再有就是可以對(duì) ch0,ch1,ch2,ch3,做詳細(xì)分類(lèi),看看它們之間都有什么樣的關(guān)系,通過(guò)觀察,我也是能發(fā)現(xiàn)什么的;通過(guò)歸納和總結(jié),就得出了TEXT編碼的可識(shí)別方法,如下:
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(); /* 文件頭兩個(gè)字節(jié)是255 254,為Unicode編碼; 文件頭三個(gè)字節(jié) 254 255 0,為UTF-16BE編碼; 文件頭三個(gè)字節(jié) 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; } } } } }
ASCII編碼的你也能識(shí)別出來(lái)?
看我的代碼
FileStream read2 = File.OpenRead(file);
byte[] dat = new byte[read2.Length];
byte[] dat_out = new byte[read2.Length - 160];
read2.Read(dat, 0, (int)read2.Length);
label1.Text = "已打開(kāi)文件,長(zhǎng)度:" + read2.Length.ToString() + " ,時(shí)間:" + DateTime.Now.ToString();
for (int i = 160; i < read2.Length; i++)
{
dat_out[i - 160] = dite[dat[i]];
}
read2.Close();
Encoding reVal;
if ((dat_out[0] == 0xEF && dat_out[1] == 0xBB && dat_out[2] == 0xBF))
{
reVal = Encoding.UTF8;
}
else if (dat_out[0] == 0xFE && dat_out[1] == 0xFF && dat_out[2] == 0x00)
{
reVal = Encoding.BigEndianUnicode;
}
else if (dat_out[0] == 0xFF && dat_out[1] == 0xFE && dat_out[2] == 0x41)
{
reVal = Encoding.Unicode;
}
else
{
reVal = Encoding.Default;
}
read = reVal.GetString(dat_out);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
FileStream read2 = File.OpenRead(file);
byte[] dat = new byte[read2.Length];
byte[] dat_out = new byte[read2.Length - 160];
read2.Read(dat, 0, (int)read2.Length);
label1.Text = "已打開(kāi)文件,長(zhǎng)度:" + read2.Length.ToString() + " ,時(shí)間:" + DateTime.Now.ToString();
for (int i = 160; i < read2.Length; i++)
{
dat_out[i - 160] = dite[dat[i]];
}
read2.Close();
Encoding reVal;
if ((dat_out[0] == 0xEF && dat_out[1] == 0xBB && dat_out[2] == 0xBF))
{
reVal = Encoding.UTF8;
}
else if (dat_out[0] == 0xFE && dat_out[1] == 0xFF && dat_out[2] == 0x00)
{
reVal = Encoding.BigEndianUnicode;
}
else if (dat_out[0] == 0xFF && dat_out[1] == 0xFE && dat_out[2] == 0x41)
{
reVal = Encoding.Unicode;
}
else
{
reVal = Encoding.Default;
}
read = reVal.GetString(dat_out);
|