PHP 內建支援 2/8/10/16 進制轉換,但業務常需自定義字元集進制 (如短網址 Base62、避免混淆字元的 Base58、自定義 30/92 進制)。本文實現通用 xbin() 函式,支援任意長度字元集作為「數字符號」,完成十進制整數與自定義進制字串的雙向轉換。
<?php
/**
* 十進制整數轉自定義進制字串
*
* @param string $charset 字元集 (長度 = 基數),如 '0123456789abcdef'
* @param int $num 非負整數
* @return string 自定義進制表示
*/
function xbin(string $charset, int $num): string {
if ($num < 0) throw new InvalidArgumentException('僅支援非負整數');
$base = strlen($charset);
if ($base < 2) throw new InvalidArgumentException('字元集至少需 2 個字元');
// 特殊情況:0
if ($num === 0) return $charset[0];
$result = '';
while ($num > 0) {
$remainder = $num % $base;
$result = $charset[$remainder] . $result; // 前置拼接
$num = (int)($num / $base);
}
return $result;
}
?>
/**
* 自定義進制字串轉十進制整數
*
* @param string $charset 字元集 (需與編碼時一致)
* @param string $str 自定義進制字串
* @return int 十進制整數
*/
function xbinDecode(string $charset, string $str): int {
$base = strlen($charset);
// 建立字元 → 數值映射表 (O(1) 查找)
$map = array_flip(str_split($charset));
$result = 0;
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
$char = $str[$i];
if (!isset($map[$char])) {
throw new InvalidArgumentException("字元 '{$char}' 不在字元集中");
}
$result = $result * $base + $map[$char];
}
return $result;
}
<?php
// 1. 八進制 (驗證內建 decoct)
$oct = '01234567';
assert(xbin($oct, 9) === '11');
assert(xbinDecode($oct, '11') === 9);
assert(decoct(9) === '11');
// 2. 十六進制 (驗證內建 dechex)
$hex = '0123456789abcdef';
assert(xbin($hex, 31) === '1f');
assert(xbinDecode($hex, '1f') === 31);
assert(dechex(31) === '1f');
// 3. 自定義 30 進制 (0-9 + a-t)
$base30 = '0123456789abcdefghijklmnopqrst';
assert(xbin($base30, 59) === '1t'); // 1*30 + 29 = 59
assert(xbinDecode($base30, '1t') === 59);
// 4. 自定義 92 進制 (可列印 ASCII 排除空白)
$base92 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()-=[];\',./{}:"><>?|';
assert(xbin($base92, 183) === '1|'); // 1*92 + 91 = 183
assert(xbinDecode($base92, '1|') === 183);
// 5. 短網址常用 Base62 (避免 0/O, 1/l 混淆可用 Base58)
$base62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$short = xbin($base62, 123456789); // '8M0k'
assert(xbinDecode($base62, $short) === 123456789);
echo "所有測試通過!\n";
?>
function xbinFull(string $charset, float $num, int $precision = 6): string {
$sign = $num < 0 ? '-' : '';
$num = abs($num);
$intPart = (int)$num;
$fracPart = $num - $intPart;
$intStr = xbin($charset, $intPart);
if ($fracPart > 0) {
$fracStr = '.';
for ($i = 0; $i < $precision; $i++) {
$fracPart *= strlen($charset);
$digit = (int)$fracPart;
$fracStr .= $charset[$digit];
$fracPart -= $digit;
if ($fracPart === 0) break;
}
return $sign . $intStr . $fracStr;
}
return $sign . $intStr;
}
| 場景 | 推薦字元集 | 基數 | 特點 |
|---|---|---|---|
| 短網址 / ID 混淆 | Base62: 0-9A-Za-z | 62 | 大小寫敏感,URL 安全 |
| 用戶可讀代碼 (避免混淆) | Base58: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz | 58 | 移除 0/O, I/l, 1/I |
| 大小寫不敏感系統 | Base32: A-Z2-7 (RFC 4648) | 32 | 不區分大小寫,人工閱讀友善 |
| 極短 ID (含特殊字元) | Base92: 可列印 ASCII | 92 | 最短長度,需 URL 編碼 |
| 數學驗證 / 教學 | 自定義任意字元 | N | 展示進制本質 |
// 進制 → 十進制
bindec('1010') // 10
octdec('12') // 10
hexdec('a') // 10
base_convert('1010', 2, 16) // 'a' (任意基數 2-36)
// 十進制 → 進制
decbin(10) // '1010'
decoct(10) // '12'
dechex(10) // 'a'
base_convert(10, 10, 2) // '1010'
PHP_INT_MAX (64位系統 9.22×10¹⁸)bcmath 或 gmp 擴充array_flip(str_split($charset)) 避免重複計算自定義進制轉換是短網址、邀請碼、分散式 ID 生成的核心技術,掌握通用實現能靈活應對各種業務編碼需求。