Red de conocimiento informático - Aprendizaje de programación - Comentarios sobre varios métodos para convertir dinámicamente la codificación UTF-8 de PHP a codificación GB

Comentarios sobre varios métodos para convertir dinámicamente la codificación UTF-8 de PHP a codificación GB

El artículo "Medición y evaluación de la conversión de dirección IP-geolocalización" menciona que, en comparación con el uso de la base de datos MySQL para almacenar datos IP, usar la función ip2addr para leer directamente el archivo de la base de datos IP es el más eficiente, mientras que usar la consulta SQL es el menos eficiente. . Sin embargo, el archivo de base de datos IP QQWry.dat está codificado en GB2312. Ahora necesito resultados de geolocalización codificados en UTF-8. Si uso el enfoque MySQL, puedo convertir los datos a codificación UTF-8 cuando estén almacenados en la base de datos, de una vez por todas. Sin embargo, el archivo QQWry.dat no se puede modificar, por lo que solo puedo obtener el resultado de la función ip2addr y luego convertirlo sobre la marcha.

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

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]);

}

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

0x552B 0x658B # CJK

0x552B 0x658B # CJKCJK

0x552c 0x5b85 # CJK

0x552C 0x752D 0x752D 0x5b85 # CJK

4 0x 30FB # Katakana MID DLE punto

0x2125 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));

$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.