У меня есть сырые данные hexdump. Как сопоставить переменную длину с множеством разных разделителей - PullRequest
0 голосов
/ 10 января 2019

data

$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";

У меня есть необработанные данные hexdump на схеме выше. 08, 09 и 1A являются разделителями. Проблема в столбце D, а F может быть 09. Можно ли сопоставить регулярное выражение? Мне нужны данные между этими разделителями.

Мой код не является точным:

m/\x08(.+?\x09?)\x09(.+?)\x1A/s;

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Кажется, что $dat[4] неверные данные. По крайней мере, первое поле должно содержать второй байт, потому что D5 указывает, что после него есть по крайней мере еще один байт.

$dat[2] также недопустимые данные, поскольку поле длины для 0x09 равно 0x03, но само поле содержит четыре символа.

$dat[5] содержит недопустимый шестнадцатеричный escape. Вместо \xEO я использую \xE0.

С этими двумя исправлениями вы можете анализировать входящие сообщения с помощью функции unpack :

my( $number, $name ) = unpack 'xwxC/ax', $d;

Шаблон для unpack означает:

x - выбросить этот байт (0x08)

w - прочитать кодированный BER номер

x - выбросить этот байт (0x09)

C - прочитать этот байт и использовать его в качестве длины для следующей строки

a - прочитать следующие байты и использовать их в качестве строковых символов

x - выбросить этот байт (0x1A)

Если вы также хотите сохранить номера полей, используйте

    unpack 'CwCC/aC', $d

По крайней мере, для показанных данных шаблон unpack работает с предположениями, которые я высказал. Если это фактические данные ASN.1, тогда должно быть гораздо больше проверок и т. Д., И если разделители полей могут отсутствовать, подход на основе регулярных выражений, показанный @ikegami, безусловно, более надежен.

Фиксированный / динамический порядок полей

Шаблон опирается на фиксированный порядок полей. Если порядок полей не обязательно будет фиксированным, вам нужно будет определить шаблон (ы) unpack на основе типа каждого поля в цикле. Это приближает подход распаковки к подходу ikegami.

my ($message_type), $d = unpack 'CA*', $d;
if( $message_type eq "\x08" ) {
    my ($number), $d = unpack 'wA*', $d;
    print "Field 0x08: $number\n";
} elsif ...

См. Следующую полную программу для фиксированного порядка полей:

#!perl
use strict;
use warnings;

my @dat;

$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\x0E\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";

@dat = grep {defined } @dat;

use Data::Dumper;

for my $d (@dat) {
    # Hardcoded message parser
    print Dumper [
        unpack 'CwCC/aC', $d
    ];

    # Dynamic message parser
    while( length $d ) {
        (my ($message_type), $d) = unpack 'aa*', $d;
        if( $message_type eq "\x08" ) {
            (my ($number), $d) = unpack 'wa*', $d;
            print "Field 0x08: $number\n";
        } elsif ( $message_type eq "\x09" ) {
            (my ($len)) = unpack 'C', $d;
            (my ($name), $d) = unpack 'C/aa*', $d;
            print "Field 0x09: $name\n";
        } elsif ( $message_type eq "\x1A" ) {
            # finished
            print "Field 0x1A\n";
        } else {
            die sprintf "Unknown message type %08x", ord($message_type);
        };
    };
};

выход

$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

Смотри также

функция распаковки

(un) параметры упаковки

0 голосов
/ 10 января 2019

Я предполагаю, что формат записи определяется следующим образом:

  1. Каждая запись состоит из полей, которые начинаются с типа (например, 08, 09, 1A).
  2. Тип поля 1A - это специальный тип, который сигнализирует об окончании записи.
  3. Все записи имеют поле типа 1A.
  4. Тип поля 08 сопровождается числом, закодированным с использованием в этом формате .
  5. Тип поля 09 сопровождается одним байтом, который определяет количество байтов в оставшейся части поля, которое выглядит как строка в кодировке ASCII. (Другое разумное предположение состоит в том, что за типом поля 09 следует один байт, который определяет количество кодовых точек, закодированных с использованием следующего UTF-8).
  6. Запись не может иметь два поля одного типа.

Я не делал никаких предположений относительно следующего:

  1. Если поле типа 08 должно присутствовать или нет.
  2. Если поле типа 09 должно присутствовать или нет.
  3. Порядок полей.

Для разбора таких записей вы можете использовать следующее:

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
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...