PHP: извлечение упакованных шестнадцатеричных чисел из строки
Я пытаюсь извлечь упакованные шестнадцатеричные числа из строки. Мое приложение связывается с сервером, который отправляет строку с заголовком, за которым следуют шестнадцатеричные числа, упакованные в 2 байта. В этой строке тысячи чисел.
Я хочу извлечь каждое сжатое 2-байтовое число и преобразовать его в число, которое можно использовать для выполнения вычислений.
Пример: string = "info:\x00\x00\x11\x11\x22\x22"
выдаст три числа 0x0000
(десятичный 0), 0x1111
(десятичное число 4369), 0x2222
(десятичное 8738)
У меня есть работающее решение (см. Ниже), но оно работает слишком медленно, когда я пытаюсь обработать несколько тысяч номеров, которые отправляет сервер. Пожалуйста, предоставьте некоторые рекомендации, чтобы ускорить мой подход.
//Works but is too slow!
//$string has the data from the server
$arrayIndex = 0;
for($index = [start of data]; $index < strlen($string); $index+=2){
$value = getNum($string, $index, $index+1);
$array[$arrayIndex++] = $value;
}
function getNum($string, $start, $end){
//get the substring we're interested in transforming
$builder = substr($string, $start, $end-$start+1);
//convert into hex string
$array = unpack("H*data", $builder);
$answer = $array["data"];
//return the value as a number
return hexdec($answer);
}
Я также пытался извлечь числа в одной команде распаковки, но это не помогло (у меня возникли проблемы с пониманием используемой строки формата)
//Not working alternate method
//discard the header (in this case 18 bytes) and put the rest of the
//number values I'm interested in into an array
$unpacked = unpack("c18char/H2*data", $value);
for($i = 0; $i < $size; $i+=1){
$data = $unpacked["data".$i];
$array[$i] = $data;
}
3 ответа
$array = array();
$len = strlen($string);
for($index = [start of data]; $index < $len; $index+=2){
$d = unpack("H*data", substr($string, $index, 2));
$array[] = hexdec($d["data"]);
}
Единственными существенными вещами, которые я сделал, было кэширование значения strlen и сокращение вызовов функций.
Вы также можете попробовать это
foreach (str_split(substr($string, [start of data]), 2) as $chunk) {
$d = unpack("H*data", $chunk);
$array[] = hexdec($d["data"]);
}
Одна вещь, которую я могу предложить, это передача строки, содержащей тысячи шестнадцатеричных чисел, по ссылке, а не по значению. Если есть, скажем, 3k числа, строка будет длинной 12k символов, с множеством вызовов функции 3k приводит к ~36M (если один байт используется на символ, ~72M, если utf8) ненужной выделенной памяти в стеке:
$arrayIndex = 0;
for($index = [start of data]; $index < strlen($string); $index+=2){
$value = getNum($string, $index, $index+1);
$array[$arrayIndex++] = $value;
}
//pass by reference rather than value
function getNum(&$string, $start, $end){
//get the substring we're interested in transforming
//$builder = substr($string, $start, $end-$start+1);
//not sure if substr takes reference or value, so implementing this way, just in case it's by value
$builder = $string[$start] . $string[$start + 1] ;
//convert into hex string
$array = unpack("H*data", $builder);
$answer = $array["data"];
//return the value as a number
return hexdec($answer);
}
Не уверен, насколько это ускорится (выделение памяти точно), но определенно стоит попробовать.
Почему бы не попробовать что-то вроде:
$string = "info:\x00\x00\x11\x11\x22\x22";
$ret = array();
preg_match_all('#\\x(\d{2})#', $string, $items);
if(isset($items[1]) && count($items[1])>0)
{
for($i=0;$i<count($items[1]);$i+=2)
{
if(isset($items[1][$i]) && isset($items[1][$i+1]))
{
$ret[] = '0x' . $items[1][$i] . $items[1][$i+1];
unset($items[1][$i]);
unset($items[1][$i+1]);
}
}
}