在早期 PHP 開發中,處理中文編碼轉換是常見挑戰。本文詳細介紹如何使用 PHP 實現 GB2312(簡體中文標準編碼)與 Unicode 數值實體(如 `全`)之間的雙向轉換,並提供多種實現方案供參考。
PHP 4.3.1 後內建 iconv 函數,可高效處理編碼轉換。但需自行實現 UTF-8 到 Unicode 碼位的轉換。
<?php
$text = "全天候自動聚焦";
// 使用正則匹配雙字節字符(GB2312 範圍)
preg_match_all("/[\x80-\xff]?./", $text, $ar);
foreach ($ar[0] as $v) {
// 先轉 UTF-8,再轉 Unicode 碼位
echo "".utf8_unicode(iconv("GB2312", "UTF-8", $v)).";";
}
// UTF-8 字符轉 Unicode 碼位(十進制)
function utf8_unicode($c) {
switch (strlen($c)) {
case 1: return ord($c);
case 2:
$n = (ord($c[0]) & 0x3f) << 6;
$n += ord($c[1]) & 0x3f;
return $n;
case 3:
$n = (ord($c[0]) & 0x1f) << 12;
$n += (ord($c[1]) & 0x3f) << 6;
$n += ord($c[2]) & 0x3f;
return $n;
case 4:
$n = (ord($c[0]) & 0x0f) << 18;
$n += (ord($c[1]) & 0x3f) << 12;
$n += (ord($c[2]) & 0x3f) << 6;
$n += ord($c[3]) & 0x3f;
return $n;
}
}
?>
<?php
$str = "TTL全天候自动聚焦";
// 使用正則替換,配合 eval 執行動態代碼
$str = preg_replace("|([0-9]{1,5});|", "\".u2utf82gb(\\1).\"", $str);
$str = "\$str=\"$str\";";
eval($str);
echo $str; // 輸出:TTL全天候自動聚焦
function u2utf82gb($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 iconv('UTF-8', 'GB2312', $str);
}
?>
此函數可同時處理 `%uXXXX`、`XXXX;`、`DDDD;` 三種格式,利用 pack 和 iconv 實現 UCS-2 到 GB2312 轉換。
function unescape($str) {
$str = rawurldecode($str);
preg_match_all("/(?:%u.{4})|.{4};|\d+;|.+/U", $str, $r);
$ar = $r[0];
foreach ($ar as $k => $v) {
if (substr($v, 0, 2) == "%u") {
$ar[$k] = iconv("UCS-2", "GB2312", pack("H4", substr($v, -4)));
} elseif (substr($v, 0, 3) == "") {
$ar[$k] = iconv("UCS-2", "GB2312", pack("H4", substr($v, 3, -1)));
} elseif (substr($v, 0, 2) == "") {
$ar[$k] = iconv("UCS-2", "GB2312", pack("n", substr($v, 2, -1)));
}
}
return join("", $ar);
}
$str = "TTL全天候自动聚焦";
echo unescape($str); // 輸出:TTL全天候自動聚焦
提供一個完整的 HTML 頁面,包含字符與 Unicode 實體雙向轉換功能,支援正向/反向模式切換。
<script language="JavaScript1.2">
function Str2Unicode(str) {
var arr = [];
for (var i = 0; i < str.length; i++) {
arr[i] = "" + str.charCodeAt(i) + ";";
}
return arr.join("");
}
function Unicode2oStr(str) {
var re = /[\da-fA-F]{1,5};/ig;
var arr = str.match(re);
if (!arr) return "";
for (var i = 0; i < arr.length; i++) {
arr[i] = String.fromCharCode(arr[i].replace(/[]/g, ""));
}
return arr.join("");
}
// ... 表單交互代碼省略 ...
</script>
內建常用字符集範圍按鈕(半角、全角、中文、日文、韓文等),可自定義範圍查看字符實體。
<script>
function showUni(min, max) {
show.document.open();
show.document.writeln("<style>body{font-size:9pt;word-break:break-all;}</style>");
show.document.writeln(min + " - " + max + "<br><br>");
for (var i = min; i <= max; i++) {
show.document.write("" + i + ";");
}
show.document.close();
}
</script>
<input type=button value="半角" onclick=showUni(32,126)>
<input type=button value="全角" onclick=showUni(65281,65374)>
<input type=button value="中文1" onclick=showUni(19968,40869)>
<!-- 更多按鈕省略 -->
早期無 iconv 時使用映射表文件 gb2312.txt 進行轉換,現已不推薦,僅供了解原理。
function gb2utf8($gb) {
if (!trim($gb)) return $gb;
$filename = "gb2312.txt";
$tmp = file($filename);
$codetable = [];
while (list($key, $value) = each($tmp)) {
$codetable[hexdec(substr($value, 0, 6))] = substr($value, 7, 6);
}
// ... 轉換邏輯省略 ...
return $utf8;
}
mb_convert_encoding 或 iconv,配合 UTF-8 統一編碼。eval 存在風險,實際部署請改用 preg_replace_callback。