Im Artikel „Auswertung der IP-Adresse -> Geografische Standortkonvertierung“ wird erwähnt, dass die Verwendung der Funktion ip2addr zum direkten Lesen der IP-Datenbankdatei im Vergleich zur Verwendung der MySQL-Datenbank zum Speichern von IP-Daten am effizientesten ist am wenigsten effizient. Aber die IP-Datenbankdatei QQWry.dat ist GB2312-kodiert. Jetzt benötige ich UTF-8-codierte Geolokalisierungsergebnisse. Wenn Sie die MySQL-Methode verwenden, können Sie die Daten beim Speichern in der Datenbank ein für alle Mal in die UTF-8-Kodierung konvertieren. Die Datei QQWry.dat kann jedoch nicht geändert werden und das Ausgabeergebnis der Funktion ip2addr kann nur dynamisch konvertiert werden.
Es gibt mindestens vier Möglichkeiten, die GB->UTF-8-Codierung dynamisch zu konvertieren:
Verwenden Sie die iconv-Erweiterung von PHP zum Konvertieren,
verwenden Sie die mb_string-Erweiterung von PHP zum Konvertieren
, verwenden Sie die Swap-Tabellenkonvertierung und die Swap-Tabelle wird mithilfe der Swap-Tabellenkonvertierung
in
der MySQL-Datenbank gespeichert , Auslagerungstabelle Die ersten beiden Methodender Speicherung in Textdateien
können nur verwendet werden, wenn der Server entsprechend eingerichtet ist (entsprechende Erweiterungen wurden kompiliert und installiert). Mein virtueller Host verfügt nicht über diese beiden Erweiterungen, daher muss ich die beiden letztgenannten Methoden in Betracht ziehen. Die ersten beiden Methoden werden in diesem Artikel nicht bewertet.
Das Auswertungsverfahren ist wie folgt (für func_ip.php lesen Sie bitte den Artikel „Auswertung der IP-Adresse -> geografische Standortkonvertierung“):
<?php
require_once ("func_ip.php");
Funktion 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;
}
Funktion 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"]);
sonst $strRet .= "??";
$i++;
} anders {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
Funktion 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]);
sonst $strRet .= "??";
$i++;
} anders {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
Funktion EncodeIp($strDotquadIp) {
$arrIpSep = explosion('.', $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]);
}
Funktion GetMicroTime() {
list($msec, $sec) = explosion(" ", microtime());
return ((double)$msec + (double)$sec);
}
for ($i = 0; $i < 100; $i++) { // Generiere zufällig 100 IP-Adressen
$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");
// Kodierungskonvertierung von MySQL-Abfragen auswerten
$dblTimeStart = GetMicroTime();
für ($i = 0; $i < 100; $i++) {
$strUTF8Region = GB2UTF8_SQL($arrAddr[$i]["region"]);
$strUTF8Address = GB2UTF8_SQL($arrAddr[$i]["address"]);
}
$dblTimeDuration = GetMicroTime() - $dblTimeStart;
//Die Auswertung endet und die Ergebnisse werden ausgegeben
echo $dblTimeDuration; echo "rn";
// Kodierungskonvertierung der Auswertungstextdateiabfrage
$dblTimeStart = GetMicroTime();
für ($i = 0; $i < 100; $i++) {
$strUTF8Region = GB2UTF8_FILE($arrAddr[$i]["region"]);
$strUTF8Address = GB2UTF8_FILE($arrAddr[$i]["address"]);
}
$dblTimeDuration = GetMicroTime() - $dblTimeStart;
//Die Auswertung endet und die Ergebnisse werden ausgegeben
echo $dblTimeDuration; echo "rn";
?>
Ergebnisse zweier Auswertungen (auf 3 Dezimalstellen genau, Einheit ist Sekunde):
MySQL-Abfragekonvertierung: 0,112
Textabfragekonvertierung: 10,590
MySQL-Abfragekonvertierung: 0,099
Textabfragekonvertierung: 10.623
Es ist ersichtlich, dass die MySQL-Methode diesmal der Dateiabfragemethode weit voraus ist. Es besteht jedoch keine Eile, jetzt die MySQL-Methode zu verwenden, da die Textdateimethode vor allem deshalb so zeitaufwändig ist, weil sie für jede Konvertierung die gesamte gb_unicode.txt in den Speicher einlesen muss und gb_unicode.txt eine Textdatei mit dem ist folgendes Format:
0x2121 0x3000 #IDEOGRAPHICSPACE
0x2122 0x3001 #IDEOGRAPHISCHES KOMMA
0x2123 0x3002 #IDEOGRAPHIC FULL STOP
0x2124 0x30FB # KATAKANA MITTLERER PUNKT
0x2125 0x02C9 # MODIFIERBUCHSTABE MACRON (Mandarin-Chinesisch erster Ton)
…
0x552A 0x6458 # <CJK>
0x552B 0x658B # <CJK>
0x552C 0x5B85 # <CJK>
0x552D 0x7A84 # <CJK>
…
0x777B 0x9F37 # <CJK>
0x777C 0x9F3D # <CJK>
0x777D 0x9F3E # <CJK>
0x777E 0x9F44 # <CJK>
Die Textdatei ist ineffizient. Erwägen Sie daher, die Textdatei in eine Binärdatei zu konvertieren und dann die Methode auf halbem Weg zu verwenden, um die Datei zu finden, ohne die gesamte Datei in den Speicher einzulesen. Das Dateiformat ist: Der Dateikopf ist 2 Byte groß und speichert die Anzahl der Datensätze. Anschließend werden die Datensätze einzeln in der Datei gespeichert. Jeder Datensatz ist 4 Byte groß, die ersten 2 Byte entsprechen dem GB-Code und die letzten 2 Byte entsprechen dem Unicode-Code. Der Konvertierungsvorgang ist wie folgt:
<?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) .
$fileGBU = fopen("gbu.dat", "wb");
fwrite($fileGBU, $strCount);
foreach ($arrCodeTable as $k => $v) {
$strData = chr($k % 256) . chr(floor($k / 256)) .
fwrite($fileGBU, $strData);
}
fclose($fileGBU);
?>
Nach der Ausführung des Programms wird die binäre GB->Unicode-Vergleichstabelle gbu.dat abgerufen und die Datensätze nach dem GB-Code sortiert, was für die Suche mit der Halbmethode praktisch ist. Die Funktion zum Transkodieren mit gbu.dat lautet wie folgt:
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) { // Suche nach halber Methode
$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;
brechen;
}
if ($intGB > $intCode) $intStart = $intMid;
sonst $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);
} anders {
$strRet .= "??";
}
$i++;
} anders {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
Fügen Sie es dem ursprünglichen Auswertungsprogramm hinzu und werten Sie die drei Methoden zweimal gleichzeitig aus, um die Daten zu erhalten (auf 3 Dezimalstellen genau, Einheit: Sekunden):
MySQL-Methode: 0,125
Textdateimethode: 10.873
Halbierungsmethode für Binärdateien: 0,106
MySQL-Methode: 0,102
Textdateimethode: 10.677
Halbierungsmethode für Binärdateien: 0,092
Es ist ersichtlich, dass die Halbierungsmethode für Binärdateien einen leichten Vorteil gegenüber der MySQL-Methode hat. Allerdings transkodieren die oben genannten Auswertungen alle kurze geografische Standorte. Was ist, wenn sie längere Texte transkodieren? Ich habe 5 Blog-RSS-2.0-Dateien gefunden, alle in GB2312 codiert. Bewerten Sie die Zeit, die zum Kodieren von 5 Dateien mit den drei Methoden benötigt wird. Die beiden Messdaten lauten wie folgt (auf 3 Dezimalstellen genau, Einheit: Sekunden):
MySQL-Methode: 7.206
Textdateimethode: 0,772
Binärdatei-Halbierungsmethode: 5.022
MySQL-Methode: 7.440
Textdateimethode: 0,766
Halbierungsmethode für Binärdateien: 5.055
Es ist ersichtlich, dass die Textdateimethode für lange Texte optimal ist, da die Transcodierung nach dem Einlesen der Transcodierungsvergleichstabelle in den Speicher sehr effizient sein kann. In diesem Fall können wir auch versuchen, es zu verbessern und die Textdateimethode so zu ändern: Die Transkodierungsvergleichstabelle wird aus der Binärdatei gbu.dat statt aus der Textdatei in den Speicher eingelesen. Die Auswertungsdaten lauten wie folgt (Genauigkeit und Einheit sind die gleichen wie oben):
Lesen Sie die Vergleichstabelle aus der Textdatei: 0,766
Nachschlagetabelle aus Binärdatei lesen: 0,831
Nachschlagetabelle aus Textdatei lesen: 0,774
Das Lesen der Vergleichstabelle aus der Binärdatei: 0,833
zeigt an, dass diese Verbesserung fehlgeschlagen ist und das Lesen der Transkodierungsvergleichstabelle aus der Textdatei effizienter ist.
Zusammenfassung: Verwenden Sie PHP, um die GB-Kodierung dynamisch in die UTF-8-Kodierung zu konvertieren. Wenn der konvertierte Text jedes Mal klein ist, ist es sinnvoll, eine Binärdatei in Kombination mit der Halbweg-Konvertierungsmethode zu verwenden. Es empfiehlt sich, eine Textdatei zum Speichern der Nachschlagetabelle zu verwenden und die Nachschlagetabelle vor der Konvertierung einmal in den Speicher einzulesen.