我正在编写一个perl脚本,它使用消息定义从一个文件中提取值,并使用它们来更新配置文件。
例如:
消息定义文件(ICD.txt):
MESSAGE: FOO_TELEM
latitude [-90,90]
longitude [-180,180]
MESSAGE: FOO_FREQUENCY
airPressure [0,50]
engineSpeed [0,65500]
FOO_TELEM消息的成员纬度范围为-90到90,经度范围为-180到180.
配置文件(Config.txt):
MessageTable
Message FOO_TELEM
Member latitude DOUBLE End-Member
Member longitude DOUBLE End-Member
End-Message
Message FOO_FREQUENCY
Member airPressure ULONG End-Member
Member engineSpeed ULONG End-Member
End-Message
End-MessageTable
我希望能够使用消息定义文件(ICD.txt)中包含的约束值更新配置文件(Config.txt),以便结果如下所示:
更新了配置文件(Config.txt):
MessageTable
Message FOO_TELEM
Member latitude DOUBLE CONSTRAINT -90 90 End-Member
Member longitude DOUBLE CONSTRAINT -180 180 End-Member
End-Message
Message FOO_FREQUENCY
Member airPressure ULONG CONSTRAINT 0 50 End-Member
Member engineSpeed ULONG CONSTRAINT 0 65500 End-Member
End-Message
End-MessageTable
我尝试过各种形式的grep来获得我需要的结果但是没有成功。任何建议将不胜感激。我愿意接受任何涉及grep,sed和/或perl的解决方案。
答案 0 :(得分:2)
这是一个镜头。我将为我的文件重复使用DATA
,因为我不应该编写开/关逻辑。
use strict;
use warnings;
my %messages;
my $current;
CONSTRAINT:
while ( <DATA> ) {
last CONSTRAINT if m/^---$/;
if ( my ( $message ) = m/^ MESSAGE: \s+ ( \S+ )/x ) {
$messages{ $message } = $current = {};
}
elsif ( my ( $name, $min, $max )
= m/^ (\w+) \s+ \[ \s* (-?\d+), \s* (-?\d+) \s* \]/x
) {
$current->{ $name } = [ $min, $max ];
}
}
while ( <DATA> ) {
chomp;
if ( my ( $msg ) = m/Message \s+ ( \S+ )/x ) {
$current = $messages{ $msg };
}
elsif ( ref( $current )
and my ( $before, $member, $after )
= m/^( \s* Member \s+ ( \w+ ) \s+ \w+ ) \s+ (.*) /x
) {
if ( my $vals = $current->{ $member } ) {
$_ = "$before CONSTRAINT @$vals $after";
}
}
say;
}
__DATA__
MESSAGE: FOO_TELEM
latitude [-90,90]
longitude [-180,180]
MESSAGE: FOO_FREQUENCY
airPressure [0,50]
engineSpeed [0,65500]
---
MessageTable
Message FOO_TELEM
Member latitude DOUBLE End-Member
Member longitude DOUBLE End-Member
End-Message
Message FOO_FREQUENCY
Member airPressure ULONG End-Member
Member engineSpeed ULONG End-Member
End-Message
End-MessageTable
答案 1 :(得分:1)
首先,编写解析器以将数据加载到以下数据结构中:
my %data = (
FOO_TELEM => {
latitude => [ -90, 90 ],
longitude => [ -180, 180 ],
},
FOO_FREQUENCY => {
latitude => [ 0, 50 ],
longitude => [ 0, 65500 ],
},
);
然后,为您的数据定义格式编写解析器。唯一的补充是当它找到$data{$message_name}{$member_name}
时查找End-Member
。
答案 2 :(得分:0)
其中任何一种都是标准格式吗?这会有所帮助。例如,如果您的Config.txt
文件是XML格式,则它看起来像这样:
<messageTable>
<message name="FOO_TELEM">
<member name="latitude" type="DOUBLE"/>
<member name="longitude" type="DOUBLE"/>
</message>
<message name="FOO_FREQUENCY">
<member name="airPressure" type="ULONG"/>
<member name="engineSpeed" type="ULONG"/>
</message>
</messageTable>
如果您的文件没有任何特定的标准格式,您可以将它们变成标准格式吗?它不一定是XML,YAML也可以。
我问的原因是Perl拥有众多模块,可以快速解析这些标准格式,使所有内容都易于操作。如果没有,您将不得不手动解析数据以提取信息。
最简单的方法是解析表并在Perl中创建一个复杂的数据结构来存储ICD.txt
文件的信息。 Perl有三种标准数据类型:Scalars(变量如$foo
),数组(变量如@foo
)和散列(变量如%hash
)。这些数据类型中的每一种都处理个别值。标量和哈希处理这些值的列表时,标量只能包含一个单独的值。
要处理更复杂的结构,您需要使用Perl References。引用允许您拥有哈希哈希值或数组数组,数组哈希值或哈希值数组等。
例如:
use strict;
use warnings;
use feature qw(say);
use autodie;
use Data::Dumper;
open my $icd_fh, "<", "icd.txt";
my %icd_data;
my $message;
while (my $line = <$icd_fh>) {
if ($line =~ /^MESSAGE: (.*)/) {
$message = $1;
}
else {
$line =~ /(.*) \[(.*),(.*)\]/;
my $message_type = $1;
my $lower_limit = $2;
my $upper_limit = $3;
if (not exists $icd_data{$message}) {
$icd_data{$message} = {};
}
$icd_data{$message}->{$message_type} = {};
$icd_data{$message}->{$message_type}->{LOWER} = $lower_limit;
$icd_data{$message}->{$message_type}->{UPPER} = $upper_limit;
}
}
say Dumper \%icd_data;
这将使您的ICD数据具有以下形状:
$VAR1 = {
'FOO_TELEM' => {
'longitude' => {
'LOWER' => '-180',
'UPPER' => '180'
},
'latitude' => {
'LOWER' => '-90',
'UPPER' => '90'
}
},
'FOO_FREQUENCY' => {
'airPressure' => {
'LOWER' => '0',
'UPPER' => '50'
},
'engineSpeed' => {
'LOWER' => '0',
'UPPER' => '65500'
}
}
};
从那里,你应该能够解析Config.txt
文件的行,并用你需要的数据修改它们。