Как я могу разобрать разделенные пробелами шестнадцатеричные строки STDIN, распакованные в Perl?

у меня есть Java-программа, которая выплевывает в шестнадцатеричном формате с разделением пространства 16 байтов необработанного пакета, полученного по сети. Поскольку я не хочу изменять этот код, я передаю результат скрипту Perl, который теоретически может просто unpack этого STDIN в узнаваемых переменных. Ниже приведен пример ввода строки в мой файл Perl:

FF FF 09 7D 10  01  07  01 00  02 00  1D 00  00 00  00 00  06 00  07 00 
|--garbage-----|c--|c--|int---|int---|int---|int---|int---|int---|int---|

(c для char / byte, int для 16-битной целочисленной переменной)

Я изначально хотел использовать unpack чтобы четко разделить каждую входную строку на переменные, которые мне нужны. Однако из-за разделителя пространства в строке я не уверен, как его обрабатывать (я могу использовать " A " в качестве шаблона, но тогда я мог бы просто использовать split!)

есть ли элегантный способ использования unpack()? Я не мастер Perl, но другой способ, как я предлагал раньше, использовать split а затем вручную преобразовать каждый hex в байт, а затем использовать битовые манипуляции и маски, чтобы получить то, что я хочу. Любой другой предложения (если unpack не спасает день)?

2 ответов


предполагая, что эти ints находятся в порядке big-endian, используйте

#! /usr/bin/perl

use warnings;
use strict;

# for demo only
*ARGV = *DATA;

while (<>) {
  my @fields = unpack "x5C2n7",
               pack "C*",
               map hex, split;

  print "[", join("][" => @fields), "]\n";
}

__DATA__
FF FF 09 7D 10 01 07 01 00 02 00 1D 00 00 00 00 00 06 00 07 00

он начинается с упаковки в байтах (C*) в соответствии с их ценностями. The unpack шаблон имеет следующие части:

  • x5 пропускает пять байт
  • C2 декодирует два unsigned char значения
  • n7 декодирует семь 16-битных больших целых чисел без знака

выход:

$ ./dump-packets
[1][7][256][512][7424][0][0][1536][1792]

Если вы хотите использовать unpack для распакованных данных, вам нужно сначала упаковать его снова. И вам нужно убрать пробелы перед этим.

другими словами,

$line =~ tr/ //d;          # remove spaces
$line = pack 'H*', $line;  # convert hex to binary
# Now you can use unpack.