Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 我有原始数据。如何使用多个不同的分隔符匹配可变长度_Regex_Perl - Fatal编程技术网

Regex 我有原始数据。如何使用多个不同的分隔符匹配可变长度

Regex 我有原始数据。如何使用多个不同的分隔符匹配可变长度,regex,perl,Regex,Perl,我有上面模式中的原始hextump数据。08、09和1A是分隔符。问题是D列和F列可能是09。可以匹配正则表达式吗?我需要这些分隔符之间的数据 我的代码不准确: $dat[1] = "\x08\xB3\xE3\x0C\x09\x07\x4D\x6F\x68\x61\x6D\x65\x64\x1A"; $dat[2] = "\x08\x84\x03\x09\x03\x53\x6F\x6C\x6C\x1A"; $dat[3] = "\x08\xD4\xEA\x0E\x09\x03\x54\x6F\x

我有上面模式中的原始hextump数据。08、09和1A是分隔符。问题是D列和F列可能是09。可以匹配正则表达式吗?我需要这些分隔符之间的数据

我的代码不准确:

$dat[1] = "\x08\xB3\xE3\x0C\x09\x07\x4D\x6F\x68\x61\x6D\x65\x64\x1A";
$dat[2] = "\x08\x84\x03\x09\x03\x53\x6F\x6C\x6C\x1A";
$dat[3] = "\x08\xD4\xEA\x0E\x09\x03\x54\x6F\x6C\x1A";
$dat[4] = "\x08\xD5\x09\x03\x55\x6F\x6C\x1A";
$dat[5] = "\x08\xD4\xEA\x09\x09\x03\x54\x6F\x6C\x1A";
$dat[6] = "\x08\xD4\xEA\xOE\x09\x09\x54\x6F\x6C\x61\x6D\x65\x64\x61\x61\x1A";
$dat[7] = "\x08\xD4\xEA\x09\x09\x09\x54\x6F\x6C\x61\x6D\x65\x64\x61\x61\x1A";

我假设记录格式定义如下:

每个记录由以类型开头的字段组成,例如08、09、1A。 字段类型1A是一种特殊类型,表示记录结束。 所有记录都有一个1A型字段。 字段类型08后面是使用编码的数字。 字段类型09后面跟着一个字节,该字节定义字段其余部分的字节数,该字节似乎是ASCII编码的字符串。另一个合理的假设是字段类型09后面跟着一个字节,该字节定义了使用UTF-8编码的代码点的数量。 一个记录不能有两个相同类型的字段。 我没有对以下内容做出任何假设:

m/\x08(.+?\x09?)\x09(.+?)\x1A/s;
是否必须存在08类型的字段。 是否必须存在类型为09的字段。 字段的顺序。 要解析此类记录,可以使用以下命令:

m/\x08(.+?\x09?)\x09(.+?)\x1A/s;
$dat[4]似乎是无效数据。至少第一个字段应该包含第二个字节,因为D5表示后面至少还有一个字节

$dat[2]也是无效数据,因为0x09的长度字段为0x03,但字段本身包含四个字符

$dat[5]包含无效的十六进制转义。我使用\xE0而不是\xEO

通过这两个更正,您可以使用以下函数解析输入消息:

for ($file) {  # Makes $_ an alias for $file.
   REC: while (1) {
      my %rec;
      FIELD: while (1) {
         my $field_start = pos() || 0;
         if (!/\G ( . )/sxgc) {
            last REC if !%rec;
            die("Premature EOF\n");
         }

         if ($type eq "\x1A") {
            last;
         }

         elsif ($type eq "\x08") {
            !exists($rec{"09"})
               or warn(sprintf("Duplicate field of type %02X at pos %s\n", $type, $field_start));

            /\G ( [\x80-\xFF]*[\x00-\x7F] ) /sxgc
               or die(sprintf("Bad field of type %02X at pos %s\n", $type, $field_start));

            $rec{"08"} = unpack("w", "$1");
         }

         elsif ($type eq "\x09") {
            !exists($rec{"09"})
               or warn(sprintf("Duplicate field of type %02X at pos %s\n", $type, $field_start));

            /\G ( . ) /sxgc
               or die(sprintf("Bad field of type %02X at pos %s\n", $type, $field_start));

            my $len = ord($1);
            length() >= pos() + $len
               or die(sprintf("Bad field of type %02X at pos %s\n", $type, $field_start));

            $rec{"09"} = substr($_, pos(), $len);
            pos() += $len;
         }

         else {
            die(sprintf("Unrecognized record type %02X at pos %s\n", $type, $field_start));
         }
       }

      # Do something with %rec
   }
}
解包模板指的是:

x-扔掉这个字节0x08

w-读取BER编码的数字

x-扔掉这个字节0x09

C-读取此字节并将其用作以下字符串的长度

a-读取下一个字节并将其用作字符串

x-扔掉这个字节0x1A

如果还想保留字段编号,请使用

my( $number, $name ) = unpack 'xwxC/ax', $d;
至少对于显示的数据,解包模板是有效的,符合我所述的假设。如果这是实际的ASN.1数据,那么应该有更多的验证等,如果字段分隔符可能丢失,那么@ikegami所示的基于regexp的方法肯定更可靠

固定/动态字段顺序 模板依赖于字段的固定顺序。如果字段顺序不一定固定,则需要根据循环中每个字段的类型确定解包模板。这使得解包方法接近池上的方法

    unpack 'CwCC/aC', $d
有关固定字段顺序,请参阅以下完整程序:

my ($message_type), $d = unpack 'CA*', $d;
if( $message_type eq "\x08" ) {
    my ($number), $d = unpack 'wA*', $d;
    print "Field 0x08: $number\n";
} elsif ...
输出 另见
你的输入格式是什么?当然,它不是图片,因为不能在图像中的文本上使用正则表达式。是Excel文件吗?还是CSV文件?您向我们显示的列的分隔符是什么?文件里有12和1A吗\x12是一个控制字符,而不是两个字符1和2。请提供答案和您的问题,告诉我们您的实际投入是什么。如果它包含控制字符,您可以使用Data::Dumper将其字符串化并显示给我们。这是原始hexdump数据。是的,F列是字节数。请再次刷新。我刚刚编辑过。是的,非常好。我紧急编辑了好几次这个问题。使用解包'xwxC/ax'可能是个有趣的主意,但我懒得去检查/解决它。令我惊讶的是,解包确实有效,但如果输入数据像OP显示的那样不可靠,而不是像某些东西所建议的那样仅仅是键入错误,那么基于正则表达式的方法就更明智了。@Corion,哦,我没有意识到数字格式是一个标准的支持包!不过,您对字段的顺序和每种类型的字段的数量做了一些额外的假设。是的,在某些时候总是需要进行错误检查/报告,所以现在解包可能不错,但这可能只是一个临时解决方案。最终需要一个合适的解析器,比如我发布的解析器。不一定要重新设计,抱歉。数据字段08只是示例,因为我急于编辑问题。其中一些是无效的@ต้องเอกมัย - 如果输入无效,您希望如何正确解析输入?!你们两个都很酷@ikegami在上一个问题上帮了我很多忙。真实的数据是非常有效的。所以我认为解包方法很容易使用。我看到有人使用延迟评估。它也很好吗/\x08.+?\x09.?{$n=ord$1;{$n}}\x1A/
$VAR1 = [
          8,
          848268,
          9,
          'Mohamed',
          26
        ];
Field 0x08: 848268
Field 0x09: Mohamed
Field 0x1A
$VAR1 = [
          8,
          515,
          9,
          'Sol',
          26
        ];
Field 0x08: 515
Field 0x09: Sol
Field 0x1A
$VAR1 = [
          8,
          1389838,
          9,
          'Tol',
          26
        ];
Field 0x08: 1389838
Field 0x09: Tol
Field 0x1A
$VAR1 = [
          8,
          1389833,
          9,
          'Tol',
          26
        ];
Field 0x08: 1389833
Field 0x09: Tol
Field 0x1A
$VAR1 = [
          8,
          1389838,
          9,
          'Tolamedaa',
          26
        ];
Field 0x08: 1389838
Field 0x09: Tolamedaa
Field 0x1A
$VAR1 = [
          8,
          1389833,
          9,
          'Tolamedaa',
          26
        ];
Field 0x08: 1389833
Field 0x09: Tolamedaa
Field 0x1A