最近在做工具的時候遇到讀取兩個文件編碼不一致的情況,但實際情況並不是用iconv轉換就可以的那麼簡單,因爲其中一個編碼是ANSI,另一個是Unicode big endian,這時候用函數mb_detect_encoding 都識別不了編碼,更別想用幾個函數就能簡單轉換了。
不過google到了一個不錯的php類,引入即可。
PHP字符編碼互轉類
<?php
/** 字符編碼轉換類, ANSI、Unicode、Unicode big endian、UTF-8、UTF-8+Bom互相轉換
* Func:
* public convert 轉換
* private convToUtf8 把編碼轉爲UTF-8編碼
* private convFromUtf8 把UTF-8編碼轉換爲輸出編碼
*/
class CharsetConv{ // class start
private $_in_charset = null; // 源編碼
private $_out_charset = null; // 輸出編碼
private $_allow_charset = array('utf-8', 'utf-8bom', 'ansi', 'unicode', 'unicodebe');
/** 初始化
* @param String $in_charset 源編碼
* @param String $out_charset 輸出編碼
*/
public function __construct($in_charset, $out_charset){
$in_charset = strtolower($in_charset);
$out_charset = strtolower($out_charset);
// 檢查源編碼
if(in_array($in_charset, $this->_allow_charset)){
$this->_in_charset = $in_charset;
}
// 檢查輸出編碼
if(in_array($out_charset, $this->_allow_charset)){
$this->_out_charset = $out_charset;
}
}
/** 轉換
* @param String $str 要轉換的字符串
* @return String 轉換後的字符串
*/
public function convert($str){
$str = $this->convToUtf8($str); // 先轉爲utf8
$str = $this->convFromUtf8($str); // 從utf8轉爲對應的編碼
return $str;
}
/** 把編碼轉爲UTF-8編碼
* @param String $str
* @return String
*/
private function convToUtf8($str){
if($this->_in_charset=='utf-8'){ // 編碼已經是utf-8,不用轉
return $str;
}
switch($this->_in_charset){
case 'utf-8bom':
$str = substr($str, 3);
break;
case 'ansi':
$str = iconv('GBK', 'UTF-8//IGNORE', $str);
break;
case 'unicode':
$str = iconv('UTF-16le', 'UTF-8//IGNORE', substr($str, 2));
break;
case 'unicodebe':
$str = iconv('UTF-16be', 'UTF-8//IGNORE', substr($str, 2));
break;
default:
break;
}
return $str;
}
/** 把UTF-8編碼轉換爲輸出編碼
* @param String $str
* @return String
*/
private function convFromUtf8($str){
if($this->_out_charset=='utf-8'){ // 輸出編碼已經是utf-8,不用轉
return $str;
}
switch($this->_out_charset){
case 'utf-8bom':
$str = "\xef\xbb\xbf".$str;
break;
case 'ansi':
$str = iconv('UTF-8', 'GBK//IGNORE', $str);
break;
case 'unicode':
$str = "\xff\xfe".iconv('UTF-8', 'UTF-16le//IGNORE', $str);
break;
case 'unicodebe':
$str = "\xfe\xff".iconv('UTF-8', 'UTF-16be//IGNORE', $str);
break;
default:
break;
}
return $str;
}
} // class end
?>
使用方法:
<?php
require "CharsetConv.class.php";
$str = file_get_contents('source/unicodebe.txt');
$obj = new CharsetConv('unicodebe', 'utf-8bom');//將Unicode big endian 轉化爲utf-8帶bom
$response = $obj->convert($str);
file_put_contents('response/utf-8bom.txt', $response, true);
?>
既然全部轉化爲utf8,那麼調用的php文件也必須是utf8編碼。
編碼科普
各種編碼在實際應用中比較容易混亂,下面從網上找的部分講解,相對比較容易理解,後門會加上自己對於這些編碼的理解。
一、ANSI
注意這裏的ANSI編碼,並非ASCII編碼,雖然它確實有點迷惑人。在簡體中文系統下,ANSI編碼代表的就是GB2312編碼。對於一個ANSI文本,英文部分使用的就是ASCII編碼,而中文部分使用的就是GB2312編碼。
二、Unicode
Unicode是用2個字節表示全世界的符號,只要選擇Unicode編碼,所有的字符都會使用2個字節進行存儲,英文字符也不例外,說到Unicode編碼,一般默認指的是UTF-16/UCS-2, little endian這種實現。
三、Unicode big endian
Unicode big endian也是Unicode,只不過是另一種實現:UTF-16/UCS-2, big endian。
BIG-ENDIAN就是低位字節排放在內存的高端,高位字節排放在內存的低端。而LITTLE-ENDIAN正好相反。
例如“王”字:Unicode爲738BH
若按Unicode-BE方式存儲,則是:73 8B
若按Unicode-LE方式存儲,就是:8B 73
四、UTF-8
UTF-8也是一種Unicode實現,因爲Unicode是對全世界的所有符號進行了獨立的編碼,也就是獨一無二的,這個編碼與實現無關,UTF-8只是在這種獨立的編碼上面進行了重新的編碼,它是一種變長的格式,根據不同的編碼,字符可能佔用1~4個字節。比如ASCII字符佔用1個字節,而漢字一般都佔用3個字節。