pack和unpack格式化字串(format string)解釋
每次pack和unpack都需要去查表,而且php對於大小端的支援也不完善,下面是我寫的一個類,流式讀寫,完全支援大小端,用起來應該方便不少。
<?php /** * Copyright (c) 2016, bookrpg, All rights reserved. * @author llj <[email protected]> * @license The MIT License */ //namespace bookrpg\util; class Endian { const BIG_ENDIAN = 'bigEndian'; const LITTLE_ENDIAN = 'littleEndian'; } class ByteArray { private $data = ''; private $position = 0; private $endian; private $isLittleEndian; public $needConvertEndian; private static $systemEndian = null; public static function systemEndian() { if(self::$systemEndian === null){ self::$systemEndian = pack('v', 1) == pack('s', 1) ? Endian::LITTLE_ENDIAN : Endian::BIG_ENDIAN; } return self::$systemEndian; } public function __construct($data = null) { $this->setEndian(self::systemEndian()); $this->data = is_null($data) ? $this->data : $data; } /* * Endian::LITTLE_ENDIAN or Endian::BIG_ENDIAN */ public function getEndian() { return $this->endian; } public function setEndian($value) { $this->endian = $value == Endian::BIG_ENDIAN ? Endian::BIG_ENDIAN : Endian::LITTLE_ENDIAN; $this->isLittleEndian = $this->endian == Endian::LITTLE_ENDIAN; $this->needConvertEndian = $this->endian != self::systemEndian(); } public function getLength() { return strlen($this->data); } public function getPosition() { return $this->position; } public function setPosition($value) { $this->position = $value; } public function getBytesAvailable() { return strlen($this->data) - $this->position; } public function clear() { $this->data = ''; $this->position = 0; } public function readBoolean() { if($this->getBytesAvailable() < 1){ return null; } $arr = unpack('@' . $this->position . '/ck', $this->data); $this->position++; return boolval($arr['k']); } public function readByte() { if($this->getBytesAvailable() < 1){ return false; } $arr = unpack('@' . $this->position . '/ck', $this->data); $this->position++; return $arr['k']; } public function readUByte() { if($this->getBytesAvailable() < 1){ return false; } $arr = unpack('@' . $this->position . '/Ck', $this->data); $this->position++; return $arr['k']; } public function readInt16() { //php缺少有符號型整數的大小端讀取,參見補碼相關知識 if(($i = $this->readUInt16()) !== false && $i > 0x7fff){ $i = -(~($i - 1) & 0xffff); } return $i; } public function readUInt16() { if($this->getBytesAvailable() < 2){ return false; } $key = $this->needConvertEndian ? ($this->isLittleEndian ? '/vk' : '/nk') : '/Sk'; $arr = unpack('@' . $this->position . $key, $this->data); $this->position += 2; return $arr['k']; } public function readInt32() { if(($i = $this->readUInt32()) !== false && $i > 0x7fffffff){ $i = -(~($i - 1) & 0xffffffff); } return $i; } public function readUInt32() { if($this->getBytesAvailable() < 4){ return false; } $key = $this->needConvertEndian ? ($this->isLittleEndian ? '/Vk' : '/Nk') : '/Lk'; $arr = unpack('@' . $this->position . $key, $this->data); $this->position += 4; return $arr['k']; } public function readInt64() { if(($i = $this->readUInt64()) !== false && $i > 0x7fffffffffffffff){ $i = -(~($i - 1)); } return $i; } /** * php has't uint64,so be sure the number is in int64.min ~ int64.max * @return [type] [description] */ public function readUInt64() { if($this->getBytesAvailable() < 8){ return false; } $key = $this->needConvertEndian ? ($this->isLittleEndian ? '/Pk' : '/Jk') : '/Qk'; $arr = unpack('@' . $this->position . $key, $this->data); $this->position += 8; return $arr['k']; } public function readFloat() { if($this->getBytesAvailable() < 4){ return false; } if($this->needConvertEndian){ $data = $this->readBytes(4); $arr = unpack('fk', strrev($data)); } else{ $arr = unpack('@' . $this->position . '/fk', $this->data); $this->position += 4; } return $arr['k']; } public function readDouble() { if($this->getBytesAvailable() < 8){ return false; } if($this->needConvertEndian){ $data = $this->readBytes(8); $arr = unpack('dk', strrev($data)); } else{ $arr = unpack('@' . $this->position . '/dk', $this->data); $this->position += 8; } return $arr['k']; } public function readBytes($count) { if($this->getBytesAvailable() < $count){ return false; } $key = '/a'. $count . 'k'; $arr = unpack('@' . $this->position . $key, $this->data); $this->position += $count; return $arr['k']; } /** * first read strlen(2byte), then read str */ public function readString() { $len = $this->readUInt16(); if($len <=0 || $this->getBytesAvailable() < $len){ return false; } $key = '/a'. $len . 'k'; $arr = unpack('@' . $this->position . $key, $this->data); $this->position += $len; return $arr['k']; } public function writeBoolean($value) { $this->data .= pack('c', $value ? 1 : 0); $this->position++; } public function writeByte($value) { $this->data .= pack('c', $value); $this->position++; } public function writeUByte($value) { $this->data .= pack('C', $value); $this->position++; } public function writeInt16($value) { //php缺少有符號型整數的大小端寫入,參見補碼相關知識 if($value < 0){ $value = -(~($value & 0xffff) + 1); } $this->writeUInt16($value); } public function writeUInt16($value) { $key = $this->needConvertEndian ? ($this->isLittleEndian ? 'v' : 'n') : 'S'; $this->data .= pack($key, $value); $this->position += 2; } public function writeInt32($value) { if($value < 0){ $value = -(~($value & 0xffffffff) + 1); } $this->writeUInt32($value); } public function writeUInt32($value) { $key = $this->needConvertEndian ? ($this->isLittleEndian ? 'V' : 'N') : 'L'; $this->data .= pack($key, $value); $this->position += 4; } public function writeInt64($value) { if ($value < 0) { $value = -(~$value + 1); } $this->writeUInt64($value); } /** * php has't uint64,so be sure the number is in int64.min ~ int64.max * @return [type] [description] */ public function writeUInt64($value) { $key = $this->needConvertEndian ? ($this->isLittleEndian ? 'P' : 'J') : 'Q'; $this->data .= pack($key, $value); $this->position += 8; } public function writeFloat($value) { $this->data .= $this->needConvertEndian ? strrev(pack('f', $value)) : pack('f', $value); $this->position += 4; } public function writeDouble($value) { $this->data .= $this->needConvertEndian ? strrev(pack('d', $value)) : pack('d', $value); $this->position += 8; } public function writeBytes($value) { $len = strlen($value); $this->data .= pack('a' . $len, $value); $this->position += $len; } /** * first read strlen(2byte), then read str */ public function writeString($value) { $len = strlen($value); $this->writeUInt16($len); $this->data .= pack('a' . $len, $value); $this->position += $len; } public function toBytes() { return $this->data; } }
測試程式碼:
$byte = new ByteArray(); $byte->setEndian(Endian::BIG_ENDIAN); $byte->writeUByte(111); $byte->writeBoolean(true); $byte->writeUInt16(21); $byte->writeUInt32(21); $byte->writeUInt64(21); $byte->writeFloat(-1.1); $byte->writeDouble(-1.1); $byte->writeString('a你好'); $byte->writeBytes('aaa'); $byte->setPosition(0); echo $byte->readUByte() . PHP_EOL; echo $byte->readBoolean() . PHP_EOL; echo $byte->readUInt16() . PHP_EOL; echo $byte->readUInt32() . PHP_EOL; echo $byte->readUInt64() . PHP_EOL; echo $byte->readFloat() . PHP_EOL; echo $byte->readDouble() . PHP_EOL; echo $byte->readString() . PHP_EOL; echo $byte->readBytes(3) . PHP_EOL;
相關推薦
pack和unpack格式化字串(format string)解釋
不能直接使用pack的格式化字串"a1a1a1",而必須在每個項後面跟上解析出來的key,key不能用數字開頭,然後用/分割。 每次pack和unpack都需要去查表,而且php對於大小端的支援也不完善,下面是我寫的一個類,流式讀寫,完全支援大小端,用起來應該方便不少。<?php /** * Copy
pytorch的pack和unpack函式
pack unpack 匯入 from torch.nn.utils.rnn import pack_padded_sequence as pack from torch.nn.utils.rnn import pad_packed_sequence as unpack 使
perl pack和unpack的使用詳解
perl pack和unpack的使用方法Pack 與unpack使用說明: pack可視為將一系列的片段的數值打包在一起,可用於對dev檔案、socket、memory的讀寫,因為這些需要一塊完整的memory,而且需要事先打包成特定格式;而unpack可以視為將將這些完
格式化字串-String.format()的使用【Java】
常規型別的格式化 String類的format()方法用於建立格式化的字串以及連線多個字串物件。熟悉C語言的同學應該記得C語言的sprintf()方法,兩者有類似之處。format()方法有兩種過載形式。 format(String format, Object… args) 新字串
格式化字串漏洞 format string exploit(一)
本文系原創,轉載請說明出處 本文為基於CTF WIKI的PWN學習 0x00 格式化字串原理 先附一張經典的圖,如下 其棧上佈局如下: some value 3.14 123456 addr of "red
[Python開發]Python中struct.pack()和struct.unpack()用法詳細說明
python中的struct主要是用來處理C結構資料的,讀入時先轉換為Python的字串型別,然後再轉換為Python的結構化型別,比如元組(tuple)啥的~。一般輸入的渠道來源於檔案或者網路的二進位制流。 1.struct.pack()和struct.unpack() 在轉化
js字串格式化方法format
/** * 設定字串format函式 * 例子: '{0}{1}.format(5,6)' */ setStringFormat() { String.prototype['format'] = function () { const e = arguments; retu
Java_51_組合_內部類詳解_字串(String類)_equals和==的區別
組合 使用組合,可以獲得更多的靈活性,你甚至可以在執行的時候才決定哪幾個類組合在一起。 使用繼承,他是一種高度耦合,派生類和基類被緊緊的綁在一起,靈活性大大降低,而且,濫用繼承,也會使繼承樹變得又大又複雜,很難理解和維護。 如果是is-a關係,用繼承。【是一個[物件]】 如果是h
Python format格式化字串(轉)
轉自: https://www.cnblogs.com/wilber2013/p/4641616.html # 位置引數 print("{0} is {1} years old".format("Wilber", 28)) print("{} is {} years old".
PHP字串處理和時間格式化整理
一、PHP字串相關 1、字串擷取(開始位置、長度) echo substr("Hello world",0,10)."<br>"; //Hello worlecho substr("Hello world",0,-1)."<br>"; //Hello worle
python字串格式化之format
用法: 它通過{}和:來代替傳統%方式 1、使用位置引數 要點:從以下例子可以看出位置引數不受順序約束,且可以為{},只要format裡有相對應的引數值即可,引數索引從0開,傳入位置引數列表可用*列表 >>> li = ['hoho',18] >>> 'm
C++ primer plus書之--C++函式和C語言字串, 結構體, string
函式和C風格字串 要將C風格字串作為引數傳遞給函式, 表示字串的方式有三種: 1.char陣列 2.用""擴起來的字串常量 3.被設定為字串地址的char指標 來看一個例子: // c風格字串例子 #include "iostream" using namespace std
Python格式化字串str.format()
Python 字串格式化解決的問題: 字串格式化是為了實現字串和變數同時輸出時按一定的格式顯示。 例如:" 一年有{}天,一天有{}小時 。".format(365,24) ==> " 一年有365天,一天有24小時。" fo
2018年12月7日 字串格式化2 format與函式1
tp7="i am \033[44;1m %(name)-25.6s\033[0m"%{"name":"sxj2343333"} print(tp7) #-為左對齊,\033[44;1m \033[0m 為選取44色號的顏色 tp1="I am {},age{}
julia:String:轉化和輸出格式化
# String: 轉化和格式化 # strings can be converted using float and Int e_str1 = "2.718" e = float(e_str1) println(5*e) #> 13.5914 num_1
Python用format格式化字串
format是是python2.6新增的一個格式化字串的方法,相對於老版的%格式方法,它有很多優點。 1.不需要理會資料型別的問題,在%方法中%s只能替代字串型別 2.單個引數可以多次輸出,引數順序可以不相同 3.填充方式十分靈活,對齊方式十分強大 4.官方推
Python學習day05-字串格式化、format字串格式化、函式(上)
一、字串格式化 ①佔位符: %s:萬能的,可以列印所有資料型別,一般用於字串 %d:列印整型 %f:列印浮點數,預設最多列印小數點後6位 ②格式化輸出: (1)普通輸出 msg='i am %s my age is %d' % ('Hello',18) prin
Python中struct pack 和struct unpack 用法詳細說明
python中的struct主要是用來處理C結構資料的,讀入時先轉換為Python的字串型別,然後再轉換為Python的結構化型別,比如元組(tuple)啥的~。一般輸入的渠道來源於檔案或者網路的二進位制流。1.struct.pack()和struct.unpack()在轉化過
Python格式化字串輸出(%與format用法)
一、%用法: 字串格式程式碼如下: 符號 說明 補充 %s 字串 %c 字元 %d 十進位制
C++ format 格式化字串實現方式
1.You can't do it directly, because you don't have write access to the underlying buffer (until C++11; see Dietrich Epp's comment). You'll