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í)別方法,如下:

 

 

復(fù)制代碼
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;
                }
            }
        }
    }
}
復(fù)制代碼

 

2
0
上一篇:刪除重復(fù)文件的程序
下一篇:文件操作工具,需者自取
posted @ 2016-11-21 11:19 小堯弟 閱讀(343) 評(píng)論(5編輯 收藏

  
#1樓 2016-11-21 14:06 墮落門(mén)徒  
用Python chardet庫(kù)豈不是省事?
  
#2樓 2016-11-21 17:20 fxyc87  
哎,你弄的也太復(fù)雜了吧?有沒(méi)有效暫不說(shuō)
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);
  
#3樓 2016-11-21 17:21 fxyc87  
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);