$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;
答案 0 :(得分:4)
我假设记录格式定义如下:
08
,09
,1A
)开头的字段组成。1A
是一种特殊类型,表示记录已结束。1A
。08
之后是使用this format编码的数字。09
后跟一个字节,该字节定义了字段其余部分中的字节数,该字节数似乎是ASCII编码的字符串。 (另一个合理的假设是,字段类型09
之后是一个字节,该字节定义了随后使用UTF-8编码的代码点的数量。)我对以下内容不做任何假设:
08
的字段。09
的字段。要解析此类记录,可以使用以下内容:
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
}
}
答案 1 :(得分:4)
似乎$dat[4]
是无效数据。至少第一个字段应包含第二个字节,因为D5
表示后面至少还有一个字节。
$dat[2]
也是无效数据,因为0x09
的长度字段为0x03
,但该字段本身包含四个字符。
$dat[5]
包含无效的十六进制转义。我使用\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
模板。这使解压缩方法接近池上的方法。
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