Pregunta

I'm trying to extract packed hexadecimal numbers from a string. My application is communicating with a server which sends a string with a header followed by 2 byte packed hexadecimal numbers. There are thousands of numbers in this string.

What I want to do is extract each 2 byte compressed number, and convert that into a number I can use to perform calculations on.

Example: string = "info:\x00\x00\x11\x11\x22\x22" will produce three numbers 0x0000 (decimal 0), 0x1111 (decimal 4369), 0x2222 (decimal 8738)

I have a working solution (see below,) but it functions too slowly when I try to process the several thousand numbers that the server sends over. Please provide some recommendations to speed up my approach.

//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);
}

I've also been attempting to extract the numbers in a single unpack command, but that is not working (I'm having some trouble understanding the format string to use)

//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;
}
¿Fue útil?

Solución

$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"]);
}

The only significant things I did was to cache the value of strlen and reduce function calls.

you could also try this

foreach (str_split(substr($string, [start of data]), 2) as $chunk) {
    $d = unpack("H*data", $chunk);
    $array[] = hexdec($d["data"]);
}

Otros consejos

One thing I can suggest is passing string containing thousands of hexadecimal number via reference, rather then value. If there is let's say 3k numbers, string is long 12k characters, with multiple of 3k function calls results in ~36M (if one byte used per char, ~72M if utf8) un-neccessary allocated memory on stack:

$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);
}

Not sure how much this speeds up (memory allocation for sure), but definitely worth a shot.

Why not trying something like:

$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]);
            }
     }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top