首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實作 BCD 編碼壓縮:十進位數字轉十六進位位元組陣列與還原

     編輯:PHP 相關知識

什麼是 BCD 編碼?

BCD(Binary-Coded Decimal,二進位編碼十進位) 是一種將十進位數字的每一位(0-9)以 4 位元二進位(半個位元組)儲存的編碼方式。例如十進位 91 在 BCD 中表示為 1001 0001(十六進位 0x91),比純二進位儲存更直觀,常用於金融、電信、嵌入式系統等需精確十進位運算的領域。

本文示範 PHP 實作 BCD 壓縮與還原:將字串形式的十進位數字(如 "0091")壓縮為位元組陣列([0, 145] 即 0x00, 0x91),並支援反向還原。

核心類別:Bytes 工具類

<?php
/**
 * PHP BCD 編碼工具類
 * 功能:十進位字串 ⇄ 十六進位位元組陣列 互轉
 * 
 * 範例:"0091" → [0, 145] (0x00, 0x91) → 還原 "0091"
 */
class Bytes {
    
    /**
     * 字串轉 ASCII 碼陣列
     * @param string $string 輸入字串
     * @return array ASCII 碼陣列
     */
    public static function getBytes($string) {
        $bytes = array();
        for ($i = 0; $i < strlen($string); $i++) {
            $bytes[] = ord($string[$i]);
        }
        return $bytes;
    }
    
    /**
     * 位元組陣列轉十六進位字串
     * @param array $bytes 位元組陣列
     * @return string 十六進位字串
     */
    public static function toStr($bytes) {
        $str = '';
        foreach ($bytes as $ch) {
            $str .= bin2hex(chr($ch));
        }
        return $str;
    }
    
    /**
     * ASCII 碼陣列轉 BCD 十六進位陣列(壓縮)
     * 每 2 個 ASCII 字元壓縮為 1 個位元組
     * 
     * @param array $asc ASCII 碼陣列
     * @param int $AscLen 陣列長度
     * @return array BCD 十六進位陣列
     */
    public static function AscToHex($asc, $AscLen) {
        $i = 0;
        $Hex = array();
        
        for ($i = 0; 2 * $i < $AscLen; $i++) {
            // 高 4 位:第一個字元
            $Hex[$i] = (chr($asc[2 * $i]) << 4);
            
            // 處理 A-F 字元(ASCII 65-70, 97-102)
            if (!(chr($asc[2 * $i]) >= '0' && chr($asc[2 * $i]) <= '9')) {
                $Hex[$i] += 0x90;
            }
            
            // 若無第二個字元則結束
            if (2 * $i + 1 >= $AscLen) {
                break;
            }
            
            // 低 4 位:第二個字元
            $Hex[$i] |= (chr($asc[2 * $i + 1]) & 0x0f);
            
            if (!(chr($asc[2 * $i + 1]) >= '0' && chr($asc[2 * $i + 1]) <= '9')) {
                $Hex[$i] += 0x09;
            }
        }
        return $Hex;
    }
    
    /**
     * BCD 十六進位陣列轉 ASCII 碼陣列(還原)
     * 每 1 個位元組還原為 2 個 ASCII 字元
     * 
     * @param array $Hex BCD 十六進位陣列
     * @param int $HexLen 陣列長度
     * @return array ASCII 碼陣列
     */
    public static function HexToAsc($Hex, $HexLen) {
        $i = 0;
        $Temp = 0;
        $Asc = array();
        
        for ($i = 0; $i < $HexLen; $i++) {
            // 取高 4 位
            $Temp = ($Hex[$i] & 0xf0) >> 4;
            if ($Temp < 10) {
                $Asc[2 * $i] = (0x30 + $Temp); // '0'-'9'
            } else {
                $Asc[2 * $i] = (0x37 + $Temp); // 'A'-'F'
            }
            
            // 取低 4 位
            $Temp = $Hex[$i] & 0x0f;
            if ($Temp < 10) {
                $Asc[2 * $i + 1] = (0x30 + $Temp);
            } else {
                $Asc[2 * $i + 1] = (0x37 + $Temp);
            }
        }
        return $Asc;
    }
}
?>

使用範例與輸出說明

<?php
require_once 'Bytes.php';

$string = '0091';

// 1. 字串轉 ASCII 碼陣列
$bytes = Bytes::getBytes($string);
// 輸出: Array ( [0]=>48 [1]=>48 [2]=>57 [3]=>49 )  // '0','0','9','1' 的 ASCII

// 2. ASCII 壓縮為 BCD(4 位字元 → 2 位元組)
$asc = Bytes::AscToHex($bytes, 4);
// 輸出: Array ( [0]=>0 [1]=>145 )  // 0x00, 0x91

// 3. BCD 轉十六進位字串顯示
echo Bytes::toStr($asc); 
// 輸出: 0091

// 4. 反向還原:BCD → ASCII(2 位元組 → 4 位字元)
$hex = Bytes::HexToAsc($asc, 2);
// 輸出: Array ( [0]=>48 [1]=>48 [2]=>57 [3]=>49 )

// 5. ASCII 轉回字串
echo Bytes::toStr($hex);
// 輸出: 0091
?>

演算法核心邏輯解析

壓縮過程

步驟輸入處理結果
1'0'(48), '0'(48)高4位: 48<<4=768(0x300) → '0'屬0-9不加0x900x00
2'9'(57), '1'(49)高4位: 57<<4=912(0x390) → 低4位: 49&0x0f=1 → 0x3910x91

註:實際程式碼中對非數字字元(A-F)有額外處理(+0x90/+0x09),支援完整十六進位字元集。

還原過程

將每個位元組拆解為高 4 位與低 4 位,分別轉回對應 ASCII 碼(0-9 對應 0x30-0x39,A-F 對應 0x41-0x46)。

應用場景與注意事項

適用場景

  • 金融交易訊息封裝(ISO 8583 等標準常用 BCD)
  • 電信通訊協定(SMPP、USSD 等)
  • 嵌入式裝置資料傳輸(節省頻寬)
  • 身分證號、銀行卡號等純數字欄位壓縮儲存

注意事項

  • 輸入長度必須為偶數,奇數長度需補零處理
  • 僅支援 0-9、A-F 字元,其他字元會產生非預期結果
  • PHP 7+ 建議改用 pack()/unpack() 內建函式處理二進位資料,效能更佳
  • 大量資料處理時,考慮使用 gmp 或 bcmath 擴充套件進行高精度運算

現代化替代方案

<?php
// 使用 PHP 內建函式簡化 BCD 處理 (PHP 5.6+)

/** 字串壓縮為 BCD 二進位字串 */
function bcdPack($str) {
    // 確保偶數長度
    if (strlen($str) % 2 !== 0) $str = '0' . $str;
    return pack('H*', $str);
}

/** BCD 二進位字串還原 */
function bcdUnpack($bcd) {
    return unpack('H*', $bcd)[1];
}

// 測試
$original = '0091';
$packed = bcdPack($original);    // 二進位字串 "\x00\x91"
$unpacked = bcdUnpack($packed);  // '0091'
echo $unpacked; // 0091
?>

pack('H*', ...) 直接將十六進位字串轉為二進位資料,unpack('H*', ...) 反向操作,程式碼更簡潔且效能更好。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved