2008-09-18 67 views
270

在我們的應用程序中,我們收到來自不同來源的文本文件(.txt.csv等)。在閱讀時,這些文件有時會包含垃圾,因爲這些文件是在不同的/未知的代碼頁中創建的。如何檢測文本文件的編碼/代碼頁

有沒有辦法(自動)檢測文本文件的代碼頁?

detectEncodingFromByteOrderMarks,在StreamReader構造,適用於UTF8和其他的Unicode標文件,但是我正在尋找一種方法來檢測代碼頁,像ibm850windows1252


感謝您的回答,這就是我所做的。

我們收到的文件來自最終用戶,他們沒有關於代碼頁的線索。接收者也是最終用戶,現在這是他們對代碼頁的瞭解:代碼頁存在並且很煩人。

解決方案:

  • 用記事本打開接收的文件,看一個亂碼一段文字。如果有人被稱爲弗朗索瓦什麼的東西,用你的人類智慧你可以猜出這個。
  • 我創建了一個小應用程序,用戶可以使用該應用程序打開該文件,並在使用正確的代碼頁時輸入用戶知道該文件將出現在文件中的文本。
  • 遍歷所有代碼頁,並顯示給出用戶提供的文本的解決方案。
  • 如果彈出更多的代碼頁,請讓用戶指定更多文本。

回答

249

你無法檢測到代碼頁,你需要被告知它。你可以分析字節並猜測它,但是這可能會導致一些奇怪的(有時候很有趣)的結果。我現在找不到它,但我確信記事本可以被誘騙顯示中文的英文文本。

無論如何,這是你需要閱讀的內容: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

具體喬爾說:

的一個最重要的事實,關於編碼

如果你完全忘記了一切,我剛纔解釋,請記住一個非常重要的事實。在不知道使用哪種編碼的情況下生成一個字符串是沒有意義的。你不能再將頭伸進沙子裏,假裝「簡單」文本是ASCII。 不過是沒有這樣的東西作爲純文本。

如果你有一個字符串,在內存中,在文件中,或者在電子郵件中,你必須知道什麼編碼它是在或無法解釋或將它正確地顯示給用戶。

+76

找到了它:http://en.wikipedia.org/wiki/Bush_hid_the_facts – 2008-09-18 08:41:25

3

StreamReader類的構造函數接受'detect encoding'參數。

+0

這只是「編碼」[鏈接](https://msdn.microsoft.com/en-us/library/system.io.streamreader%28v=vs.110%29.aspx)這裏..和描述說我們必須提供編碼.. – SurajS 2015-03-09 06:36:53

+0

@SurajS:看看其他重載。 – leppie 2015-03-09 06:45:34

+0

原作者想要檢測文件的編碼,該文件可能沒有BOM標記。 StreamReader根據簽名檢測來自BOM表頭的編碼。 公衆的StreamReader( \t流流, \t布爾detectEncodingFromByteOrderMarks ) – ibondre 2015-08-14 01:16:49

30

如果你想檢測非UTF編碼(即沒有BOM),你基本上是對文本的啓發式和統計分析。您可能需要查看Mozilla paper on universal charset detectionsame link, with better formatting via Wayback Machine)。

+8

有趣的是我的Firefox 3.05安裝檢測頁面爲UTF-8,可見一些問號-IN-A-鑽石字形,儘管源具有meta-tag for Windows-1252。手動更改字符編碼可正確顯示文檔。 – devstuff 2008-12-29 19:45:30

+5

您的句子「如果您希望檢測非UTF編碼(即沒有BOM)」稍有誤導性; unicode標準不建議向utf-8文檔添加BOM! (並且這個建議或者缺乏這個建議是許多令人頭疼的根源)。 ref:http://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 – Tao 2011-05-19 09:35:12

+0

這樣做是爲了在不累積冗餘BOM的情況下連接UTF-8字符串。此外,UTF-8不需要字節順序標記,例如與UTF-16不同。 – sashoalm 2013-08-14 08:17:41

0

得到了同樣的問題,但沒有找到一個好的解決方案,但自動檢測它。 現在即時使用PsPad(www.pspad.com);)工作正常

4

我已經做在Python類似的東西。基本上,你需要大量的從各種編碼,這是通過滑動兩個字節的窗口分解並存儲在字典(散列)的樣本數據,鍵連接在字節對編碼提供的列表中的值的。

鑑於字典(散),你把你的輸入文字和:

  • ,如果它與任何BOM字符( '\ XFE \ XFF' 爲UTF-16-BE,「\ XFF \ XFE開始「爲UTF-16-LE,‘\ XEF \ XBB \ XBF’爲UTF-8等),我把它當作建議
  • 如果沒有,那麼把文本的足夠大的樣本,採取一切字節對樣本並選擇字典中建議的最不常用的編碼。

如果你還採樣UTF編碼的文本是做開始與任何BOM,第二步將覆蓋那些從第一步下滑。

到目前爲止,它爲我工作(樣本數據和後續的輸入數據是各種語言的字幕)與減少錯誤率。

16

不能檢測編碼頁

這顯然是錯誤的。每個網頁瀏覽器都有某種通用字符集檢測器來處理沒有任何編碼指示的頁面。 Firefox有一個。你可以下載代碼,看看它是如何做到的。請參閱一些文檔here。基本上,這是一種啓發式的方法,但其效果非常好。

給定文本的合理數量的,甚至有可能檢測到的語言。

Here's another one我只是使用谷歌發現:

0

由於它基本上可以歸結爲啓發式,它可以幫助使用先前接收到的文件的編碼從同一來源的第一個暗示。

大多數人(或應用)做的東西在幾乎相同的順序每一次,經常在同一臺機器上,所以它很可能是當Bob創建一個.csv文件,並將其發送給瑪麗,它會始終使用Windows-1252或他的機器默認的任何設備。

如果可能的話有點客戶培訓從來沒有傷害任何:-)

0

我其實是在尋找的檢測文件編碼的通用,而不是編程方式,但我沒有發現呢。 我也用不同的編碼測試發現的是,我的文字是UTF-7。

所以在這裏我先在做: StreamReader的文件=文件。OpenText的(fullfilename);

我不得不將它更改爲: StreamReader file = new StreamReader(fullfilename,System.Text.Encoding.UTF7);

OpenText的假定它是UTF-8。

你也可以創建這樣 新的StreamReader(fullfilename,真),第二個參數意味着它應該嘗試從文件的byteordermark檢測的編碼,但沒有我的情況下工作的StreamReader。

8

我知道這個問題已經很晚了,這個解決方案不會吸引某些人(因爲它以英語爲中心的偏見和缺乏統計/經驗測試),但它對我來說非常好,特別是對於處理上傳的CSV數據:

http://www.architectshack.com/TextFileEncodingDetector.ashx

優點:

  • BOM檢測內置
  • 默認/備用編碼定製
  • 相當可靠(在我的經驗),用於容納用UTF-8和Latin-1的樣式文件的混合異國情調的數據(例如法國名字)的西歐式爲基礎的文件 - 基本上大部分美國和西歐的環境。

注意:我是寫這門課的人,所以很明顯帶上一粒鹽! :)

-2

我用這個代碼來檢測Unicode和Windows默認的ANSI代碼頁讀取文件時。對於其它值編碼的內容的檢查是必要的,手動地或通過編程。這可以去用文字保存相同的編碼它被打開時。 (我用VB.NET)

'Works for Default and unicode (auto detect) 
Dim mystreamreader As New StreamReader(LocalFileName, Encoding.Default) 
MyEditTextBox.Text = mystreamreader.ReadToEnd() 
Debug.Print(mystreamreader.CurrentEncoding.CodePage) 'Autodetected encoding 
mystreamreader.Close() 
19

你從http://code.google.com/p/ude/

public static void Main(String[] args) 
{ 
    string filename = args[0]; 
    using (FileStream fs = File.OpenRead(filename)) { 
     Ude.CharsetDetector cdet = new Ude.CharsetDetector(); 
     cdet.Feed(fs); 
     cdet.DataEnd(); 
     if (cdet.Charset != null) { 
      Console.WriteLine("Charset: {0}, confidence: {1}", 
       cdet.Charset, cdet.Confidence); 
     } else { 
      Console.WriteLine("Detection failed."); 
     } 
    } 
}  
7

尋找不同的解決方案,我發現

https://code.google.com/p/ude/

這個解決方案是有點重。

我需要一些基本的編碼檢測的基礎上,4個字節的第一和可能的XML字符集探測 - 所以我從網上花了一些示例源代碼並添加略作修改的

http://lists.w3.org/Archives/Public/www-validator/2002Aug/0084.html

版本寫Java的。

public static Encoding DetectEncoding(byte[] fileContent) 
    { 
     if (fileContent == null) 
      throw new ArgumentNullException(); 

     if (fileContent.Length < 2) 
      return Encoding.ASCII;  // Default fallback 

     if (fileContent[0] == 0xff 
      && fileContent[1] == 0xfe 
      && (fileContent.Length < 4 
       || fileContent[2] != 0 
       || fileContent[3] != 0 
       ) 
      ) 
      return Encoding.Unicode; 

     if (fileContent[0] == 0xfe 
      && fileContent[1] == 0xff 
      ) 
      return Encoding.BigEndianUnicode; 

     if (fileContent.Length < 3) 
      return null; 

     if (fileContent[0] == 0xef && fileContent[1] == 0xbb && fileContent[2] == 0xbf) 
      return Encoding.UTF8; 

     if (fileContent[0] == 0x2b && fileContent[1] == 0x2f && fileContent[2] == 0x76) 
      return Encoding.UTF7; 

     if (fileContent.Length < 4) 
      return null; 

     if (fileContent[0] == 0xff && fileContent[1] == 0xfe && fileContent[2] == 0 && fileContent[3] == 0) 
      return Encoding.UTF32; 

     if (fileContent[0] == 0 && fileContent[1] == 0 && fileContent[2] == 0xfe && fileContent[3] == 0xff) 
      return Encoding.GetEncoding(12001); 

     String probe; 
     int len = fileContent.Length; 

     if(fileContent.Length >= 128) len = 128; 
     probe = Encoding.ASCII.GetString(fileContent, 0, len); 

     MatchCollection mc = Regex.Matches(probe, "^<\\?xml[^<>]*encoding[ \\t\\n\\r]?=[\\t\\n\\r]?['\"]([A-Za-z]([A-Za-z0-9._]|-)*)", RegexOptions.Singleline); 
     // Add '[0].Groups[1].Value' to the end to test regex 

     if(mc.Count == 1 && mc[0].Groups.Count >= 2) 
     { 
      // Typically picks up 'UTF-8' string 
      Encoding enc = null; 

      try { 
       enc = Encoding.GetEncoding(mc[0].Groups[1].Value); 
      }catch (Exception) { } 

      if(enc != null) 
       return enc; 
     } 

     return Encoding.ASCII;  // Default fallback 
    } 

這足以從文件中讀取可能首先1024個字節,但我加載整個文件。

2

工具「uchardet」很好地利用每個字符集的字符頻率分佈模型。較大的文件和更多的「典型」文件有更多的信心(顯然)。

在Ubuntu上,你只需apt-get install uchardet

在其他系統上,獲取源,使用&文檔瀏覽:https://github.com/BYVoid/uchardet

0

至於附加到ITmeze後,我用這個函數C#端口的輸出轉換爲Mozilla通用字符檢測

private Encoding GetEncodingFromString(string encoding) 
    { 
     try 
     { 
      return Encoding.GetEncoding(encoding); 
     } 
     catch 
     { 
      return Encoding.ASCII; 
     } 
    } 

MSDN

5

如果有人正在尋找一個93.9%的溶液。這個工作對我來說:

public static class StreamExtension 
{ 
    /// <summary> 
    /// Convert the content to a string. 
    /// </summary> 
    /// <param name="stream">The stream.</param> 
    /// <returns></returns> 
    public static string ReadAsString(this Stream stream) 
    { 
     var startPosition = stream.Position; 
     try 
     { 
      // 1. Check for a BOM 
      // 2. or try with UTF-8. The most (86.3%) used encoding. Visit: http://w3techs.com/technologies/overview/character_encoding/all/ 
      var streamReader = new StreamReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), detectEncodingFromByteOrderMarks: true); 
      return streamReader.ReadToEnd(); 
     } 
     catch (DecoderFallbackException ex) 
     { 
      stream.Position = startPosition; 

      // 3. The second most (6.7%) used encoding is ISO-8859-1. So use Windows-1252 (0.9%, also know as ANSI), which is a superset of ISO-8859-1. 
      var streamReader = new StreamReader(stream, Encoding.GetEncoding(1252)); 
      return streamReader.ReadToEnd(); 
     } 
    } 
} 
0

打開文件AkelPad(或只是複製/粘貼亂碼),去編輯 - >選擇 - >重新編碼 - >勾選「自動檢測」。

相關問題