最近在做工具的时候遇到读取两个文件编码不一致的情况,但实际情况并不是用iconv转换就可以的那么简单,因为其中一个编码是ANSI,另一个是Unicode big endian,这时候用函数mb_detect_encoding 都识别不了编码,更别想用几个函数就能简单转换了。
不过google到了一个不错的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
?>
使用方法:
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编码,并非ASCII编码,虽然它确实有点迷惑人。在简体中文系统下,ANSI编码代表的就是GB2312编码。对于一个ANSI文本,英文部分使用的就是ASCII编码,而中文部分使用的就是GB2312编码。
Unicode是用2个字节表示全世界的符号,只要选择Unicode编码,所有的字符都会使用2个字节进行存储,英文字符也不例外,说到Unicode编码,一般默认指的是UTF-16/UCS-2, little 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也是一种Unicode实现,因为Unicode是对全世界的所有符号进行了独立的编码,也就是独一无二的,这个编码与实现无关,UTF-8只是在这种独立的编码上面进行了重新的编码,它是一种变长的格式,根据不同的编码,字符可能占用1~4个字节。比如ASCII字符占用1个字节,而汉字一般都占用3个字节。