2010-05-21 93 views
7

我想檢測一些文本的編碼(使用PHP)。 爲此,我使用mb_detect_encoding()函數。PHP中的mb_detect_order()的奇怪行爲

問題是,如果我使用mb_detect_order()函數更改可能的編碼順序,該函數將返回不同的結果。

請看下面的例子

$html = <<< STR 
ちょっとのアクセスで落ちてしまったり、サーバー障害が多いレンタルサーバーを選ぶとあなたのビジネス等にかなりの影響がでてしまう可能性があります。特に商売をされている個人の方、法人の方は気をつけるようにしてください 
STR; 
mb_detect_order(array('UTF-8','EUC-JP', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2')); 
$originalEncoding = mb_detect_encoding($str); 
die($originalEncoding); // $originalEncoding = 'UTF-8' 

但是如果你改變編碼的mb_detect_order順序()的結果會有所不同:

mb_detect_order(array('EUC-JP','UTF-8', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2'));   
die($originalEncoding); // $originalEncoding = 'EUC-JP' 



所以我的問題是:
這是爲什麼發生?
在PHP中有沒有一種方法可以正確無誤地檢測文本的編碼?

回答

5

這就是我期望發生的事情。

檢測算法可能只是繼續嘗試按照您在mb_detect_order中指定的編碼順序,然後返回字節流有效的第一個編碼。

更聰明的東西需要統計方法(我認爲機器學習是常用的)。

編輯: this article更智能的方法。

由於其重要性,自動字符集檢測已經在Mozilla或Internet Explorer等主流Internet應用程序中實現。它們非常準確和快速,但是實施在個案基礎上應用了許多特定領域的知識。與他們的方法相反,我們的目標是簡單的算法,它可以統一應用於每個字符集,並且該算法基於完善的標準機器學習技術。我們還研究了語言和字符集檢測之間的關係,並比較了基於字節的算法和基於字符的算法。我們使用樸素貝葉斯(NB)和支持向量機(SVM)。

+0

非常感謝! – Termos 2010-05-21 11:14:08

5

不是。不同的編碼通常有很大的重疊區域,如果你測試的字符串在重疊內部存在,那麼兩種編碼都是可以接受的。

例如,對於字母a-z,utf-8和ISO-8859-1是相同的。字符串「hello」在兩個編碼中都有相同的字節序列。

這正是爲什麼首先有一個mb_detect_order()函數,因爲它可以讓你說出當這些衝突發生時你更希望發生什麼。你想要「你好」是utf-8還是ISO-8859-1?

+0

我想有很多符號在2種不同的編碼中重疊。 如果是這樣,我如何選擇最適合一些文本的編碼? 換句話說 - 「我如何選擇使用哪種特定文本進行編碼而不會丟失任何數據」編碼? – Termos 2010-05-21 10:38:47

+0

我會選擇最靈活的編碼,最具體的最後。所以,我寧願使用utf-8,因爲它會對日文文本和所有其他語言進行編碼,而像ISO-8859-1這樣的文本看起來可能適合給定的文本樣本,如果要添加它會遇到問題非歐洲人物。真的,如果你正在處理很多不同的國際字符集,並且你不知道他們會提前做什麼,爲什麼要嘗試和檢測 - 只是使用一些始終有效的東西。 – 2010-05-21 10:43:24

1

mb_detect_encoding查看mb_detect_order()中的第一個字符集條目,然後循環輸入$ html匹配字符,不管該字符是否位於字符集的有效字符集內。如果每個字符匹配,則返回true;如果有任何字符失敗,它將轉到mb_detect_order()中的下一個字符集並再次嘗試。

The wikipedia list of charsets是查看組成每個字符集的字符的好地方。

由於這些字符集值重疊('UTF-8'和'EUC-JP'中均存在字符x8fA1EF),即使它是每個字符集中完全不同的字符,也會被視爲匹配項。因此,除非任何字符值存在於一個字符集中,而不存在於另一個字符集中,否則mb_detect_encoding無法識別哪些字符集無效;並會返回數組中可能有效的第一個字符集。

據我所知,沒有確定字符集的方法。如果您對可能遇到的字符集有一個合理的概念,那麼PHP的「最佳猜測」方法可以得到幫助,並根據每個字符集中的空白(無效字符)相應地排列列表。 最好的解決方案是「知道」字符集。如果您要從另一個頁面抓取您的html,請在該頁面的標題中查找字符集標識符。

如果你確實想要變得聰明,你可以嘗試識別寫入html的語言,可能使用Π或0123-c在PHP/IR中描述的類似語言。

2

請記住mb_detect_encoding()不知道數據是什麼編碼。您可能會看到一個字符串,但函數本身只能看到一串字節。因此,它需要猜測編碼是什麼 - 例如如果字節僅在0-127範圍內,則ASCII將爲UTF-8,如果有ASCII字節和128+字節僅存在於成對或更多對象中,則等等。

正如你可以想象的那樣,鑑於上下文,可靠地檢測編碼是相當困難的。

就像rihk說的那樣,這就是mb_detect_order()函數的用途 - 你基本上提供了你最好的猜測數據的可能性。你經常使用UTF-8文件嗎?那麼很可能你的東西不太可能是UTF-16,即使mb_detect_encoding()可以這樣猜測。

您可能還想查看Artefactolink以獲得更深入的視圖。

例的情況下Internet Explorer採用了一些有趣的編碼,如果未指定任何猜測(@link,科:「要自動檢測網站的語言」)這是造成上了編碼是理所當然的,在過去的網站怪異的行爲。你可能會發現一些有趣的東西,如果你谷歌周圍。它使得一個很好的例子甚至統計方法可以適得其反,以及爲什麼編碼猜測一般是有問題的。