I have to parse data strings returned by GIA10N module. The response string consists of 9 bytes ASCII codes with the pattern
^#[0-9A-F]{2}\$[0-9A-F]{4}/$
.
Description:
DIGITS 123456789
CODE #FF$DDDD/
# -- Response token
FF -- Function code 00-FF
$ -- delimiter
DDDD -- Data value 0000-FFFF
/ -- Terminal symbol
Example:
#0A$F831 -- means value -1999 from function 0A
Usually the sscanf function will do the job in C to decode this string.
#include <stdio.h>
int parseData(char *data, int prn) {
char ff[3] = "\0";
unsigned int udddd = 0;
int sdddd = 0;
if (sscanf(data,"#%2s$%X/",ff,&udddd) !=2) {
printf("ERROR parsing %s\n", data);
return 0;
}
sdddd = (int) udddd;
if (sdddd & 0x8000)
sdddd -= 0x10000;
if (prn)
printf("CODE:%s PARSED: %s %d\n", data, ff, sdddd);
return 1;
}
int main(int argc, char **argv)
{
parseData("#0A$F831/", 1);
return 0;
}
With a runtime:
$ gcc test-scan.c -o test-scan
$ time ./test-sprintf
CODE: #0A$F831/ PARSED: -1999
real 0m0.003s
user 0m0.000s
sys 0m0.000s
In perl the function sscanf in conjuction with the format %X is not avialable. I have to tailor and split the message and do the hex/ 16 bit conversion magic which is much slower.
#!/usr/bin/env perl
use warnings;
use strict;
sub parseData($$) {
my ($msg, $print) = @_;
my ($ff,$dddd) = split /\$/, substr($msg, 1, length($msg)-2);
$dddd = hex($dddd);
$dddd -= 0x10000 if $dddd & 0x8000;
printf "CODE: %s PARSED: %s %d\n", $msg, $ff, $dddd
if $print;
}
parseData('#0A$F831/', 1);
Check the perl runtime:
$ time ./test-scan.pl
CODE: #0A$F831/ PARSED: 0A -1999
real 0m0.012s
user 0m0.008s
sys 0m0.000s
I there an other way to speed this up without using another language?
Addendum
According to the answers and concepts of ike and polar bear and my approach:
#!/usr/bin/env perl
use warnings;
use strict;
use Benchmark qw( cmpthese );
my %tests = (
ike => q{
my ($ff, $dddd) = $msg =~ m{^#([0-9A-F]{2})\$([0-9A-F]{4})/\z}
or die("Error parsing \"$msg\"\n");
$dddd = hex($dddd);
},
huck => q{
(my ($ff,$dddd) = split(/\$/, substr($msg, 1, length($msg)-2))) == 2
or die("Error parsing \"$msg\"\n");
$dddd = hex($dddd);
},
pbear => q{
my($ff,$dddd) = unpack('xA2xA4',$msg);
$dddd = hex($dddd);
},
);
$_ = "use strict; use warnings; our \$msg; for (1..1000) { $_ }"
for values %tests;
local our $msg = '#0A$F831/';
cmpthese(-3, \%tests);
I got this benchmark results:
/usr/bin/perl -w "bench-cvx-data.pl"
Rate ike huck pbear
ike 1070/s -- -33% -41%
huck 1596/s 49% -- -12%
pbear 1816/s 70% 14% --