如何在perl中有效地解析表达式'^#[0-9A-F] {2} \ $ [0-9A-F] {4} / $'

哈克芬

我必须解析GIA10N模块返回的数据字符串。响应字符串由9个字节的ASCII码组成,带有模式

    ^#[0-9A-F]{2}\$[0-9A-F]{4}/$

描述:

      DIGITS  123456789
        CODE  #FF$DDDD/
           #  -- Response token
          FF  -- Function code 00-FF
           $  -- delimiter
        DDDD  -- Data value 0000-FFFF
           /  -- Terminal symbol

例:

     #0A$F831  -- means value -1999 from function 0A

通常,sscanf函数将在C中完成此字符串的解码工作。

    #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;
    }

使用运行时:

    $ gcc test-scan.c -o test-scan
    $ time ./test-sprintf
    CODE: #0A$F831/ PARSED:  -1999

    real    0m0.003s
    user    0m0.000s
    sys     0m0.000s    

在perl中,与格式%X结合使用的sscanf函数不可使用。我必须定制和拆分消息,然后执行十六进制/ 16位转换魔术,这要慢得多。

    #!/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);

检查perl运行时:

    $ time ./test-scan.pl
    CODE: #0A$F831/ PARSED: 0A -1999

    real    0m0.012s
    user    0m0.008s
    sys     0m0.000s

我还有其他方法可以在不使用其他语言的情况下加快速度吗?

附录

根据ike北极熊的答案和概念以及我的方法:


    #!/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);

我得到了这个基准测试结果:

    /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%    --

池上
^#[0-9A-F]{2}\$[0-9A-F]{4}/$

匹配9或10个字符。我想你是说

^#[0-9A-F]{2}\$[0-9A-F]{4}/\z

您的代码简化为以下内容:

my ($ff, $dddd) = $msg =~ m{^#([0-9A-F]{2})\$([0-9A-F]{4})/\z}
   or die("Error parsing \"$msg\"\n");

$dddd = hex($dddd);

也就是说,这比您的版本不过,它更具可读性。

以下内容与我的内容同等可读,与您的同等快,但没有验证:

my ($ff, $dddd) = unpack('x a2 x a4', $msg);
$dddd = hex($dddd);

就是说,12 ms是perl为我简单加载所需的时间(尽管在另一台计算机上只有5 ms)。

$ time perl -e1

real    0m0.012s
user    0m0.016s
sys     0m0.000s

是否正在尝试优化耗时少于1毫秒的内容?

所以我写了一个基准。为了我,

  • 您的版本花费了1/1232000 s = 0.81μs
  • 我的版本花了1/636000 s = 1.3μs

基准测试:

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

$_ = "use strict; use warnings; our \$msg; for (1..1000) { $_ }"
   for values %tests;

local our $msg = '#0A$F831/';
cmpthese(-3, \%tests);

代表输出:

       Rate  ike huck
ike   752/s   -- -39%
huck 1232/s  64%   --

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

相当于/ [^ a-f0-9] / i的python正则表达式

指定称为的Unicode字符的“ U \ + [0-9A-F] {4,6}”表示法是什么?

如何构造正好为[0-9a-f]类型的38个字符的正则表达式?

正则表达式无效:"/^[+]?[0-9]{0,1}[-.]?\(?([0-9]{3})\)?[-.]?([0 -9]{3})[-. ]?([0-9]{4})$/gm" in javscript

.Net Core WCF 客户端抛出 WinHttpException 错误 0x2f9a

正则表达式模式^ [a-z0-9]([_.-]?[a-z0-9] +)* / [a-z0-9](([_。]?|-{ 0,2})[a-z0-9] +)* $

Javascript正则表达式/ ^(19 | 20)([0-9] {2})-([0-9] {2} | 0 [0-9] {1})-([0-9] {2} | 0 [0-9] {1})$ / g未找到日期作为输入值

如何在不获取“ SomeType @ 2f92e0f4”的情况下打印Java对象?

用sed eval标志在shell管道中用正确的unicode字符替换“ / U + [0-9A-Fa-f] {4} /”

0x742808F2 处未处理的异常:Microsoft C++ 异常:std::out_of_range 位于内存位置 0x0055E9E4

pgstatindex - [42P01] 错误:关系“idx_b527c53b636333c0a9f8e0edc4”不存在

如何使用正则表达式检查字符串,该字符串包含12个字符且包含0-9a-f?

AddressSanitizer:PC 0x0000003a86fc bp 0x7ffeebd5f9d0 sp 0x7ffeebd5f9c8处地址0x6020000000b4上的堆缓冲区溢出

Java模式匹配无法找到具有正则表达式[A-Z0-9 ._%+-] + @ [A-Z0-9 .-] {3,65} \。[AZ] {2,4}的电子邮件

函数调用向量v(f(0(0),f(1),...,f(2))

错误:“ F”不是有效的基于文件的资源名称字符:基于文件的资源名称只能包含小写的az,0-9或下划线

在bash中,如何将Unicode代码点[0-9A-F]转换为可打印的字符?

错误:Boost_Mutex.exe中0x76f6f9d2处的异常(第一次机会):0xC0000008:指定了无效的句柄

java.lang.NumberFormatException:对于输入字符串:“ 505c621128f97f31c5870f2a9e2d274fa432bd0

ng 新想写入 '/Users/USERNAME/.npm/_cacache/index-v5/aa/9a'

emv标签0x9F37不可预测的数字长度

TypeError:f0()接受1个位置参数,但给出了9个

尝试从软盘复制文件时出现错误0x800706F9

频繁的BSOD 0x9F driver_power_state_failure

无法克隆对象<keras.wrappers.scikit_learn.KerasClassifier对象为0x7f9d95dd50f0>,因为构造函数未设置

清除算法以生成类型为(0)到(0,1,2,3,4,5,6,7,8,9)的所有集合

需要解释bash grep正则表达式grep -E'(^ | [^ 0-9。])'2 * .c

我如何设计一个以1开始并以0(1,2,3,4,5,6,7,8,9,0)结束的int循环

UICollectionView接收到具有不存在索引路径的单元格的布局属性:<NSIndexPath:0x79fe0f20> {length = 2,path = 0-4}