最近在做工具的时候遇到读取两个文件编码不一致的情况,但实际情况并不是用iconv转换就可以的那么简单,因为其中一个编码是ANSI,另一个是Unicode big endian,这时候用函数mb_detect_encoding 都识别不了编码,更别想用几个函数就能简单转换了。

不过google到了一个不错的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个字节。