php对gb编码动态转utf-8编码的几种方法评测

作者&投稿:松何 (若有异议请与网页底部的电邮联系)
~
在《IP地址-地理位置转换的测评》一文中提到用ip2addr函数直接读取IP数据库文件是效率最高的,相比用MySQL数据库存储IP数据,用SQL查询是效率最低的。但是IP数据库文件QQWry.dat是GB2312编码的。现在我需要UTF-8编码的地理位置结果。如果用MySQL方法,可以在数据存入数据库时就转换为UTF-8编码,一劳永逸。但是QQWry.dat文件又无法修改,只能把ip2addr函数的输出结果再进行动态转换。
动态转换GB-UTF-8编码至少有四种方法:
用PHP的iconv扩展转换
用PHP的mb_string扩展转换
用对换表转换,对换表存储在MySQL数据库中
用对换表转换,对换表存储在文本文件中
前两种方法要服务器作了相应设置(编译安装了相应扩展)才能使用。我的虚拟主机没有这两个扩展,只好考虑后两种方法。前两个方法本文也不进行测评。
测评程序如下(func_ip.php参见《IP地址-地理位置转换的测评》一文):
?php
require_once ("func_ip.php");
function u2utf8($c) {
$str = "";
if ($c
0x80) {
$str .= $c;
} elseif ($c
0x800) {
$str .= chr(0xC0 | $c
6);
$str .= chr(0x80 | $c
0x3F);
} elseif ($c
0x10000) {
$str .= chr(0xE0 | $c
12);
$str .= chr(0x80 | $c
6
0x3F);
$str .= chr(0x80 | $c
0x3F);
} elseif ($c
0x200000) {
$str .= chr(0xF0 | $c
18);
$str .= chr(0x80 | $c
12
0x3F);
$str .= chr(0x80 | $c
6
0x3F);
$str .= chr(0x80 | $c
0x3F);
}
return $str;
}
function GB2UTF8_SQL($strGB) {
if (!trim($strGB)) return $strGB;
$strRet = "";
$intLen = strlen($strGB);
for ($i = 0; $i
$intLen; $i++) {
if (ord($strGB{$i})
127) {
$strCurr = substr($strGB, $i, 2);
$intGB = hexdec(bin2hex($strCurr)) - 0x8080;
$strSql = "SELECT code_unicode FROM nnstats_gb_unicode
WHERE code_gb = ".$intGB." LIMIT 1"
;
$resResult = mysql_query($strSql);
if ($arrCode = mysql_fetch_array($resResult)) $strRet .= u2utf8($arrCode["code_unicode"]);
else $strRet .= "??";
$i++;
} else {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
function GB2UTF8_FILE($strGB) {
if (!trim($strGB)) return $strGB;
$arrLines = file("gb_unicode.txt");
foreach ($arrLines as $strLine) {
$arrCodeTable[hexdec(substr($strLine, 0, 6))] = hexdec(substr($strLine, 7, 6));
}
$strRet = "";
$intLen = strlen($strGB);
for ($i = 0; $i
$intLen; $i++) {
if (ord($strGB{$i})
127) {
$strCurr = substr($strGB, $i, 2);
$intGB = hexdec(bin2hex($strCurr)) - 0x8080;
if ($arrCodeTable[$intGB]) $strRet .= u2utf8($arrCodeTable[$intGB]);
else $strRet .= "??";
$i++;
} else {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
function EncodeIp($strDotquadIp) {
$arrIpSep = explode('.', $strDotquadIp);
if (count($arrIpSep) != 4) return 0;
$intIp = 0;
foreach ($arrIpSep as $k = $v) $intIp += (int)$v * pow(256, 3 - $k);
return $intIp;
//return sprintf('%02x%02x%02x%02x', $arrIpSep[0], $arrIpSep[1], $arrIpSep[2], $arrIpSep[3]);
}
function GetMicroTime() {
list($msec, $sec) = explode(" ", microtime());
return ((double)$msec + (double)$sec);
}
for ($i = 0; $i
100; $i++) { // 随机产生100个ip地址
$strIp = mt_rand(0, 255).".".mt_rand(0, 255).".".mt_rand(0, 255).".".mt_rand(0, 255);
$arrAddr[$i] = ip2addr(EncodeIp($strIp));
}
$resConn = mysql_connect("localhost", "netnest", "netnest");
mysql_select_db("test");
// 测评MySQL查询的编码转换
$dblTimeStart = GetMicroTime();
for ($i = 0; $i
100; $i++) {
$strUTF8Region = GB2UTF8_SQL($arrAddr[$i]["region"]);
$strUTF8Address = GB2UTF8_SQL($arrAddr[$i]["address"]);
}
$dblTimeDuration = GetMicroTime() - $dblTimeStart;
// 测评结束并输出结果
echo $dblTimeDuration; echo " ";
// 测评文本文件查询的编码转换
$dblTimeStart = GetMicroTime();
for ($i = 0; $i
100; $i++) {
$strUTF8Region = GB2UTF8_FILE($arrAddr[$i]["region"]);
$strUTF8Address = GB2UTF8_FILE($arrAddr[$i]["address"]);
}
$dblTimeDuration = GetMicroTime() - $dblTimeStart;
// 测评结束并输出结果
echo $dblTimeDuration; echo " ";
?
测评两次结果(精确到3位小数,单位是秒):
MySQL查询转换:0.112
文本查询转换:10.590
MySQL查询转换:0.099
文本查询转换:10.623
可见这次是MySQL方法遥遥领先于文件查询法。但是现在还不急于使用MySQL方法,因为文本文件方法之所以如此耗时,主要因为它每次转换都要把整个gb_unicode.txt读入内存,而gb_unicode.txt又是文本文件,格式如下:
0x2121 0x3000 # IDEOGRAPHIC SPACE
0x2122 0x3001 # IDEOGRAPHIC COMMA
0x2123 0x3002 # IDEOGRAPHIC FULL STOP
0x2124 0x30FB # KATAKANA MIDDLE DOT
0x2125 0x02C9 # MODIFIER LETTER MACRON (Mandarin Chinese first tone)

0x552A 0x6458 # CJK
0x552B 0x658B # CJK
0x552C 0x5B85 # CJK
0x552D 0x7A84 # CJK

0x777B 0x9F37 # CJK
0x777C 0x9F3D # CJK
0x777D 0x9F3E # CJK
0x777E 0x9F44 # CJK
文本文件效率较低,于是考虑把文本文件转换为二进制文件,然后用折半法查找这个文件,而不需要把整个文件读入内存。文件格式为:文件头2字节,存储记录数;接着一条接一条记录存入文件,每条记录4字节,前2字节对应GB代码,后2字节对应Unicode代码。转换程序如下:
?php
$arrLines = file("gb_unicode.txt");
foreach ($arrLines as $strLine) {
$arrCodeTable[hexdec(substr($strLine, 0, 6))] = hexdec(substr($strLine, 7, 6));
}
ksort($arrCodeTable);
$intCount = count($arrCodeTable);
$strCount = chr($intCount % 256) . chr(floor($intCount / 256));
$fileGBU = fopen("gbu.dat", "wb");
fwrite($fileGBU, $strCount);
foreach ($arrCodeTable as $k = $v) {
$strData = chr($k % 256) . chr(floor($k / 256)) . chr($v % 256) . chr(floor($v / 256));
fwrite($fileGBU, $strData);
}
fclose($fileGBU);
?
执行程序后就获得了二进制的GB-Unicode对照表gbu.dat,并且数据记录按GB代码排了序,便于折半法查找。使用gbu.dat进行转码的函数如下:
function GB2UTF8_FILE1($strGB) {
if (!trim($strGB)) return $strGB;
$fileGBU = fopen("gbu.dat", "rb");
$strBuf = fread($fileGBU, 2);
$intCount = ord($strBuf{0}) + 256 * ord($strBuf{1});
$strRet = "";
$intLen = strlen($strGB);
for ($i = 0; $i
$intLen; $i++) {
if (ord($strGB{$i})
127) {
$strCurr = substr($strGB, $i, 2);
$intGB = hexdec(bin2hex($strCurr)) - 0x8080;
$intStart = 1;
$intEnd = $intCount;
while ($intStart
$intEnd - 1) { // 折半法查找
$intMid = floor(($intStart + $intEnd) / 2);
$intOffset = 2 + 4 * ($intMid - 1);
fseek($fileGBU, $intOffset);
$strBuf = fread($fileGBU, 2);
$intCode = ord($strBuf{0}) + 256 * ord($strBuf{1});
if ($intGB == $intCode) {
$intStart = $intMid;
break;
}
if ($intGB
$intCode) $intStart = $intMid;
else $intEnd = $intMid;
}
$intOffset = 2 + 4 * ($intStart - 1);
fseek($fileGBU, $intOffset);
$strBuf = fread($fileGBU, 2);
$intCode = ord($strBuf{0}) + 256 * ord($strBuf{1});
if ($intGB == $intCode) {
$strBuf = fread($fileGBU, 2);
$intCodeU = ord($strBuf{0}) + 256 * ord($strBuf{1});
$strRet .= u2utf8($intCodeU);
} else {
$strRet .= "??";
}
$i++;
} else {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
把其加到原来的测评程序,对三种方法同时测评2次得到数据(精确到3位小数,单位:秒):
MySQL方法:0.125
文本文件方法:10.873
二进制文件折半法:0.106
MySQL方法:0.102
文本文件方法:10.677
二进制文件折半法:0.092
可见二进制文件折半法还比MySQL法略有优势。但是上述测评都是对短的地理位置进行转码,如果对较长的文本转码又如何呢?我找来5个Blog的RSS 2.0文件,都是GB2312编码。测评三种方法对5个文件编码耗费的时间,2次测量数据如下(精确到3位小数,单位:秒):
MySQL方法:7.206
文本文件方法:0.772
二进制文件折半法:5.022
MySQL方法:7.440
文本文件方法:0.766
二进制文件折半法:5.055
可见对长的文本是用文本文件的方法最优,因为转码对照表读入内存后,转码就可以很高效了。既然如此,我们还可以尝试改进一下,把文本文件方法改为:转码对照表从二进制文件gbu.dat读入内存,而不是文本文件。测评数据如下(精度和单位同上):
从文本文件读入对照表:0.766
从二进制文件读入对照表:0.831
从文本文件读入对照表:0.774
从二进制文件读入对照表:0.833
表明这次改进失败了,从文本文件读入转码对照表更高效。
总结:用PHP对GB编码到UTF-8编码的动态转换,如果每次转换的文本很小,适宜用二进制文件结合折半法转换;如果每次转换的文本较大,适宜用文本文件存储转码对照表,并在转换前一次性把对照表读入内存。



仿宋_GB2312和仿宋是一种字体吗?
仿宋是字体名称,而GB2312是字符编码名称,它是简体中文编码的一种,简体中文自1980年代以来通常使用中华人民共和国国家标准总局公布的GB 2312,以及其后继的GBK和GB 18030中文编码。近年来随着Unicode跨语言编码集的出现,也被广泛使用。所以通常说的仿宋就基本上是仿宋_GB2312了。简体中文系统环境支持国标 ...

HP a6355cn 硬盘标注500GB实际464.78GB正常吗?
算500G是以1000进级 算464.78G是以1024进级的!

PHP的。UTF-8编码的网页下面,如何将urlencode转成GB2312编码的
echo urlencode(iconv('utf-8', 'gb2312', '中国人'));先把 中国人 编码转成 gb2312,然后再urlencode编码一次 参考资料:http:\/\/www.deephp.com

hpdl580gen9gbod模式设置
根据百度文库查询可知,设置HPDL580Gen9的BOD模式,可以按照以下步骤进行:1.进入BIOS,选择AdvancedSystemOptions,然后检查RAID配置存储控制器选项。2.确认引导模式是高级安全引导配置中的遗留模式还是UEFI模式。3.如果设置为LegacyEnable,按Ctrl+I进入电源打开HP屏幕上的IntelRAID控制台进行配置。在HPDL580Ge...

做HP后硬盘内存与实际不符。原640G现各盘相加596G。。为什么哩...
众所周知,在计算机中是采用二进制,这样造成在操作系统中对容量的计算是以每1024为一进制的,每1024字节为1KB,每1024KB为1MB,每1024MB为1GB,每1024GB为1TB;而硬盘厂商在计算容量方面是以每1000为一进制的,每1000字节为1KB,每1000KB为1MB,每1000MB为1GB,每1000GB为1TB,这二者进制上的差异...

实惠商务本 HP ProBook 6460b首发评测
HP ProBook 6460b 笔记本规格参数名称参数规格处理器Intel(R) Core(TM) i5-2410M芯片组Intel HM65标配内存1 x 2GB DDR3 1333硬盘750 GB , 7200 RPM显卡AMD Radeon HD 6470M (512 MB)屏幕14英寸(16:9)1366×768 LED网络\/无线Intel(R) 82579V (1000M) \/ Broadcom 4313 (802.11b\/g\/n)外部接口3个USB...

HP UNIX 使用VI 和more 打开有中文字符文件显示乱码! 请问怎么修改_百度...
LC_MESSAGES="en_GB.UTF-8"LC_ALL=en_GB.UTF-8 如果不是的话可以通过设置 export LC_ALL=en_GB.UTF-8 将当前session的编码设为UTF-8 2,文件的编码确认为UTF-8,Unix的系统的编码也是UTF-8,为什么VI打开后显示的为乱码呢?问题出在Putty的设置,从Unix传输到Putty本地显示的过程也需要设置,...

HP StorageWorks DAT40X6i (C5716A)重要参数
HP StorageWorks DAT40X6i (C5716A)的数据记录格式非常多样化,支持ANSI\/ISO\/ECMA标准的DDS-2格式,以及更高级别的DDS-3和DDS-4格式,其中DDS-4的单个介质容量达到40GB,而DDS-3则为24GB。这款产品的存储容量基础规格为120GB,但通过压缩技术,您可以期待更高效的存储利用,压缩后的存储容量提升至...

惠普(HP) Scanjet 7000n 扫描仪EWS 无法正常访问,怎么解决呢?谢谢...
原来 HP Scanjet 7000n 的EWS 支持浏览器编码是“Unicode(UTF-8)”,而中文环境下的IE 浏览器默认的编码是“简体 中文(GB2312)”,所以导致HP Scanjet 7000n 的EWS 无法正常工作。解决方法:只需要把 IE 浏览器的编码设置成“自动选择”就可以解决此问题。具体设置方法:打开IE——查看——编码—...

HP403d出现乱码怎么处理
如果是属于汉字显示出现的问题,你仔细检查一下是否有字符编码设置相关选项?如果有的话,你把字符编码格式设置成:GB-2312(简体),再试一试看看。

江汉区18833003403: php中怎么将GB18030转换为UTF - 8编码 -
查府更年: 可以使用iconv函数对编码进行转换,iconv("gb18030", "utf-8", "要转换的字符串"); iconv详细用法如下: iconv — 字符串按要求的字符编码来转换 string iconv ( string $in_charset, string $out_charset, string $str)将字符串 str 从 in_...

江汉区18833003403: php 急急急 一个二维数组 编码格式为gb2312如何转换utf - 8再循环输出 -
查府更年: forech ($arr as $i=> $v) { foreach ($v as $i=> $value) { $arr[$i][$j] = iconv('gb2312', 'utf-8',$arr[$i][$j]);} }//编码转换 print_r($arr);//输出

江汉区18833003403: php gb2312转换UTF - 8编码 -
查府更年: <?php header("Content-Type:text/html; charset=GB2312");//定义页面编码方式gb2312 echo urlencode("百度");//gb2312编码的 echo "<br>";//换行 echo urlencode(iconv('GB2312', 'UTF-8', '百度'));//utf-8编码的 echo "<br>"; ...

江汉区18833003403: php gb2312转换UTF - 8编码 -
查府更年: urlencode是在URL传参时如果直接传中文可能会出问题(对中文参数支持部完善),所以先编码.输出的时候用UrlDecode解码就可以了.如果你要输出的不是URL没必要用urlencode....

江汉区18833003403: php 怎么将任意编码的内容转换成utf - 8 -
查府更年: 最简单的:$str = iconv("gbk", "utf-8//ignore", $str); 或者:$str = mb_convert_encoding($str, "utf-8", "gbk"); 稍微解释一下 //ignore 的意思是转换不了的字符就忽略.建议把这个写上.否则遇到转换不了的字符会报错.gbk替换成你需要转换的编码就可以了.

江汉区18833003403: 如何在PHP中进行GB2312与UTF - 8的互换 -
查府更年: <?phpecho iconv("GB2312", "UTF-8", "这里是你要转换的字符串");?>

江汉区18833003403: PHP中如何把一个字符串转换为utf -
查府更年: 1、把GBK 编码字串转换成 UTF-8 编码字串 view plaincopy to clipboardprint?<?phpheader("content-Type: text/html; charset=Utf-8");// 注意将此文件存...

江汉区18833003403: php 转编码 GBK繁体转utf8简体 -
查府更年: 分两步试下,把gbk转成gb2312,再把gb2312转成utf-8

江汉区18833003403: 求utf8与gb2312字符编码互转的php代码 -
查府更年: function autoCharset($string, $from='gbk', $to='utf-8') { $from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from; $to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to; if (strtoupper($from) === strtoupper($to) || empty($string) || (is_scalar($string) && !is_string($string)...

江汉区18833003403: php 转码gb2312 - >utf8,要怎么转呢,谢谢了. -
查府更年: iconv<?php$text = "This is the Euro symbol '€'.";echo 'Original : ', $text, PHP_EOL;echo 'TRANSLIT : ', iconv("UTF-8", "ISO-8859-1//TRANSLIT", $text), PHP_EOL;echo 'IGNORE : ', iconv("UTF-8", "ISO-8859-1//IGNORE", $text), PHP_EOL;echo 'Plain : ', iconv("UTF-8", "ISO-8859-1", $text), PHP_EOL;?>

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网