Comentarios sobre varios métodos para convertir dinámicamente la codificación UTF-8 de PHP a codificación GB
Existen al menos cuatro métodos para convertir dinámicamente la codificación GB-UTF-8:
Utilice la extensión iconv de PHP para la conversión
Utilice la extensión mb_string de PHP Convert p>
Convertir usando una tabla de intercambio almacenada en una base de datos MySQL
Convertir usando una tabla de intercambio almacenada en un archivo de texto
Convertir usando una tabla de intercambio almacenada en un archivo de texto la tabla de intercambio se utiliza para la conversión
Los dos primeros métodos son los siguientes. /p>
Los dos primeros métodos sólo se pueden utilizar si el servidor se ha configurado adecuadamente (las extensiones correspondientes se han compilado e instalado). Mi proveedor de alojamiento web no tiene ninguna de estas extensiones, por lo que tuve que considerar los dos últimos métodos. Este artículo no evalúa los dos primeros métodos.
El procedimiento de evaluación es el siguiente (para func_ip.php, consulte el artículo "Evaluación de conversión de dirección IP y geolocalización"): php
require_once ("func_ip.php");
función u2utf8($c) {
$str = ""
si ($c)
si ($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
p>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;
}
función GB2UTF8_SQL($strGB) {
if (!trim($strGB)) devuelve $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 = "SELECCIONE code_unicode DESDE nnstats_gb_ unicode
DONDE code_gb = ".
DONDE code_gb = ".LIMIT 1"
$resResult = mysql_query( $strSql);
if ($arrCode = mysql_fetch_array($resResult)) $strRet = u2utf8($arrCode["code_unicode"]);
else $strRet = ". ?" ;
p>$i++;
} else {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
función GB2UTF8_FILE($strGB) {
si (!trim($strGB) ) devuelve $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++;
} más {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
función EncodeIp($strDotquadIp) {
$arrIpSep = explotar( '.' , $strDotquadIp);
si (count($arrIpSep) != 4) devuelve 0;
$intIp = 0;
foreach ( $arrIpSep como $k = $v) $intIp += (int)$v * pow(256, 3 - $k);
return $intIp;
//return sprintf('%02x%02x%02x%02x%02x', $arrIpSep[0], $arrIpSep[1], $arrIpSep[2], $arrIpSep[3]);
} p>
función GetMicroTime() {
lista( $msec, $sec) = explotar(" ", microtime()
return ((double)$msec); + (double)$sec);
}
for ($i = 0; $i
100; $i++) { // Genera 100 aleatoriamente Dirección IP
$strIp = mt_rand(0, 255).".".mt_rand(0, 255).."
$strIp = mt_rand(0, 255).. " .mt_rand(0, 255).."
$strIp = mt_rand(0, 255)..".mt_rand(0, 255
$arrAddr[$i] = ip2addr(EncodeIp($strIp));
}
$resConn = mysql_connect("localhost", "netnest", "netnest ");
mysql_select_db ("test");
//Mida la conversión de codificación de consultas MySQL
$dblTimeStart = GetMicroTime();
for ($i = 0; $i
100; $i++) {
$strUTF8Región = GB2UTF8_SQL($arrAddr[$i]["región"]);
$strUTF8Address = GB2UTF8_SQL($arrAddr[$i]["dirección"]);
}
dblTimeStart = GetMicroTime();
for ($i = 0; $i
100; $i++) {
$strUTF8Región = GB2UTF8_FILE($arrAddr[$i]["región"]);
$ strUTF8Address = GB2UTF8_FILE($arrAddr[$i]["dirección"]);
}
$dblTimeDuration = GetMicroTime() - $dblTimeStart;
//La medición finaliza y se emiten los resultados
echo $dblTimeDuration echo " ";
Resultado de las dos mediciones (3 decimales, en segundos):
Conversión de consultas MySQL: 0,112
Conversión de consultas de texto: 10,590
Conversión de consultas MySQL: 0.099
Conversión de consultas de texto: 10.623
Se puede ver que esta vez el método MySQL está muy por delante del método de consulta de archivos. Pero no tenemos que apresurarnos al método MySQL todavía, porque la razón principal por la que el método del archivo de texto consume tanto tiempo es porque tiene que leer el gb_unicode.txt completo en la memoria cada vez que se convierte, y el gb_unicode.txt es un archivo de texto con el siguiente formato:
0x2121 0x3000 # ESPACIO IDEOGRAFICO
0x2122 0x3001 # COMA IDEOGRAFICA
0x2123 0x3002 # PUNTO IDEOGRAFICO
0x2124 0x30FB
0x2124 0x30FB # KATAKANA MEDIO PUNTO
0x2125 0x02C9 # LETRA MODIFICADORA MACRON (primer tono de chino mandarín)
0x552A 0x6458 # CJK p>
0x552B 0x658B # CJK
0x552B 0x658B # CJKCJK
0x552c 0x5b85 # CJK
0x552C 0x752D 0x752D 0x5b85 # CJK
4 0x 30FB # Katakana MID DLE punto0x2125 0x552D 0x7A84# CJK
0x777B 0x9F37 # CJK
0x777C 0x9F3D # CJK
0x777D 0x9F3E # CJK
0x777E 0x9F44 # CJK
Los archivos de texto son ineficientes, por lo que consideramos convertir el archivo de texto a un archivo binario y luego buscar el archivo por la mitad sin leer el archivo completo en la memoria.
El formato del archivo es el siguiente: los primeros 2 bytes del archivo almacenan el número de registros y luego los registros se almacenan en el archivo uno por uno. Cada registro tiene 4 bytes, los primeros 2 bytes corresponden a la codificación GB y el último. 2 bytes corresponden a la codificación Unicode. El procedimiento de conversión es el siguiente: php
$arrLines = file("gb_unicode.txt");
foreach ($arrLines as $strLine) {
$arrCodeTable[ hexdec(substr($strLine, 0, 6))] = hexdec(substr($strLine, 7, 6));
}
ksort($arrCodeTable) ;
p>$intCount = count($arrCodeTable);
$ strCount = chr($intCount % 256) .chr(floor($intCount / 256)); p>
$fileGBU = fopen("gbu.dat", "wb");
fwrite($fileGBU, $strCount);
foreach ($arrCodeTable como $ k = $v) {
$strData = chr($k % 256) .chr(piso($k / 256)) chr($v % 256) .chr(piso($v / . 256));
fwrite($fileGBU, $strData);
}
fclose($fileGBU
Después del Cuando se ejecuta el programa, se generarán GB binarios: rutina Unicode gbu.dat. Además, los registros de datos están ordenados según el código estándar nacional y son fáciles de encontrar doblándolos por la mitad.
La función para transcodificar usando gbu.dat es la siguiente:
función 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;
mientras ($intStart
$intEnd - 1) { // Doblar - mitad encontrar
$intMid = piso(($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;
descanso;
}
if ($intGB
$intCode) $intStart = $intMid;
si no $intEnd = $intMid;< / p>
}
$intOffset = 2 + 4 * ($intStart - 1);
fseek($fileGBU, $intOffset);
$strBuf = fread($fileGBU, 2);
$intCode = ord($strBuf{0}) + 256 * ord($strBuf{1}) ;
si ( $intGB == $intCode) {
$strBuf = fread($fileGBU, 2);
$intCodeU = ord($strBuf{0}) + 256 * ord( $ strBuf{1});
$strRet .= u2utf8($intCodeU);
} else {
$strRet = "?" /p>
p>
}
$i++;
} else {
$strRet .= $strGB{$i};
}
}
}
return $strRet;
}
Agregue esto al programa de evaluación original, evalúe todo
Tres métodos 2 veces para obtener datos (con una precisión de 3 decimales, unidad: segundos):
Método MySQL: 0,125
Método de archivo de texto: 10,873
Binario método de reducción a la mitad de archivos: 0.106
Método MySQL: 0.102
Método de archivo de texto: 10.677
Método de reducción a la mitad de archivos binarios: 0.092
Puede Se puede ver que el método de reducción a la mitad del archivo binario es ligeramente mejor que el método MySQL. Pero las medidas anteriores son todas para transcodificación de ubicación geográfica corta. ¿Qué pasa si se trata de transcodificación de texto largo? Encontré cinco archivos RSS 2.0 de blog, todos codificados en GB2312. Para medir el tiempo necesario para que los tres métodos codifiquen estos 5 archivos, los 2 resultados de la medición son los siguientes (con una precisión de 3 decimales, en segundos):
Método MySQL: 7.206
Método de archivo de texto: 0.772
Método de plegado de archivos binarios: 5.022
Método MySQL: 7.440
Método de archivo de texto: 0.766
Medio método de archivo binario: 5.055
Se puede ver que para textos largos, el método de archivo de texto es la mejor opción, porque la tabla de transcodificación se lee en la memoria y la eficiencia de transcodificación es muy alta. En este caso, también podemos intentar mejorar el método del archivo de texto y cambiarlo para leer la tabla de transcodificación en el archivo binario gbu.dat en la memoria en lugar de un archivo de texto. Los datos de evaluación son los siguientes (la precisión y la unidad son las mismas que las anteriores):
Lea la tabla de comparación de transcodificación del archivo de texto: 0,766
Lea la tabla de comparación de transcodificación del binario archivo: 0.831
Leer referencia cruzada de transcodificación del archivo de texto: 0.774
Leer referencia cruzada de transcodificación del archivo binario: 0.833
Indica que esta mejora falló, leer la transcodificación del código de un archivo de texto es más eficiente.
Resumen: Para la conversión dinámica de codificación GB a UTF-8 usando PHP, si el texto convertido cada vez es pequeño, es adecuado usar archivos binarios combinados con el método de reducción a la mitad si el texto se convierte cada vez; es grande, es adecuado utilizar un archivo de texto para almacenar la tabla de conversión y leer la tabla de conversión en la memoria al mismo tiempo antes de la conversión.