String 解析来自分隔块的数据
我有一个日志文件内容多块String 解析来自分隔块的数据,string,perl,parsing,String,Perl,Parsing,我有一个日志文件内容多块/begin CHECK/结束检查如下所示: /开始检查 Var_AAA “说明AAA” 数据类型UBYTE 最大值为255。 地址0xFF0011 /结束检查 /开始检查 Var_BBB “说明BBB” 数据类型UBYTE 最大值为255。 地址0xFF0022 /结束检查 ... 我想提取变量名及其地址,然后像这样写入一个新文件 姓名地址 Var_AAA=>0xFF0011 Var_BBB=>0xFF0022 我正在考虑($start,$keyword,$end)
/begin CHECK
<代码>/结束检查如下所示:
/开始检查
Var_AAA
“说明AAA”
数据类型UBYTE
最大值为255。
地址0xFF0011
/结束检查
/开始检查
Var_BBB
“说明BBB”
数据类型UBYTE
最大值为255。
地址0xFF0022
/结束检查
...
我想提取变量名及其地址,然后像这样写入一个新文件
姓名地址
Var_AAA=>0xFF0011
Var_BBB=>0xFF0022
我正在考虑($start,$keyword,$end)
来检查每个块,并仅提取关键字后面的数据
#/usr/bin/perl
严格使用;
使用警告;
my$input='input.log';
my$output='output.out';
我的($start,$keyword,$end)=(“^\/begin CHECK\n\n”,“ADDRESS”,“'\/end CHECK”);
我的@block;
#打开输入文件进行读取
打开(我的$in、、$output)或die“无法打开文件“$output”进行写入:$!”;
打印(“将变量名及其地址从$input复制到$output\n”);
而($in){#每行输入
如果(/$start/i../$end/i){#块匹配
按@块,$\;
}
如果(/$end/i){
对于(@block){
如果(/\s+$keyword/){
打印$out join(“”,@block);
最后;
}
}
@块=();
}
关闭$in或die“无法关闭文件“$input”:$!”;
}
关闭$out或die“无法关闭文件“$output”:$!”;
但我被处决后什么都没有。有人能给我推荐一个示例吗?大多数东西看起来都不错,但第一个问题是您的start regex造成的:
'^\/begin CHECK\n\n'
您正在从文件中读取行,但在一行中查找两个换行符。这永远不会匹配,因为一行的结尾正好是一个换行符(除非您更改$/
,但这是另一个主题)。如果要匹配行的发送,可以使用$
(或\z
)锚定:
这是我删减的节目。您可以调整它以完成所有其他需要完成的工作:
use v5.10;
use strict;
use warnings;
use Data::Dumper;
my ($start, $keyword, $end) = (qr{^/begin CHECK$}, qr(^ADDRESS ), qr(^/end CHECK));
while (<DATA>) #For each line of input
{
state @block;
chomp;
if (/$start/i .. /$end/i) #Block matching
{
push @block, $_ unless /^\s*$/;
}
if( /$end/i )
{
print Dumper( \@block );
@block = ();
}
}
使用v5.10;
严格使用;
使用警告;
使用数据::转储程序;
我的($start,$keyword,$end)=(qr{^/begin CHECK$},qr(^地址),qr(^/end CHECK));
while()#用于每行输入
{
状态@块;
咀嚼;
如果(/$start/i../$end/i)#块匹配
{
推送@block,$\uu除非/^\s*$/;
}
如果(/$end/i)
{
打印转储程序(\@块);
@块=();
}
}
在那之后,你就不能读取数据了。您需要将文件句柄放入
(行输入操作符)中:
while()
文件句柄将在程序结束时自动关闭。如果你想自己关闭它们,那很好,但在你完成之前不要这样做。在过程中的
完成之前,不要关闭$in
。以下是代码中的一些问题
- 您使用的是
while($in)
,而不是while()
,因此您的程序从不读取输入文件
- 当
读取循环时,关闭中的输入文件句柄,因此只能读取一条记录
您的$start
正则表达式模式是'^\/begin CHECK\n\n'
。单引号使程序搜索反斜杠n反斜杠n
而不是换行符换行符
如果(/\s+$keyword/)
查找任意类型的多个空格字符,后跟空格,后跟地址
,$keyword
的内容,则测试。在数据中的任何位置都不存在前面有空格的地址
你也写了太多没有测试的东西。您应该首先自己编写读取循环,并确保数据正确输入,然后在测试之间每次添加两行或三行代码。在测试之前编写90%的功能是一种非常糟糕的方法
将来,为了帮助您解决这样的问题,我将向您指出堆栈溢出上链接的优秀资源
这里唯一稍微模糊的是范围运算符/$start/i/$end/i
返回一个有用的值;我已将其复制到$status
中。运算符第一次匹配时,结果将为1;第二次2等。最后一次不同,因为它是一个使用工程符号(如9E0
)的字符串,因此它的计算结果仍然正确,但您可以使用/E/
检查最后一次匹配。我使用了==1
和/E/
来避免将开始行和结束行推到@block
我不认为这里有任何其他过于复杂的东西,你在
使用严格;
使用警告;
使用autodie;#自动处理错误的IO状态
使用列表::Util'max';
my($input,$output)=qw/input.log output.txt/;
打开我的$in_fh,,$output;
my$w=max map{length$->[0]}@vars;
printf$out_fh“%-*s=>%s\n”,$w,@$u代表[qw/Name-Address/],@vars;
关闭$OFH;
输出
Name=>地址
Var_AAA=>0xFF0011
Var_BBB=>0xFF0022
更新
无论如何,我会写这样的东西。它产生与上面相同的输出
使用严格;
使用警告;
使用autodie;#自动处理错误的IO状态
使用列表::Util'max';
my($input,$output)=qw/input.log output.txt/;
我的$data=do{
打开我的$in_fh,,$output;
my$w=max map{length$->[0]}@vars;
printf$out_fh“%-*s=>%s\n”,$w,@$u代表[qw/Name-Address/],@vars;
关闭$OFH;
在windows中使用命令提示符。在MacOS或Unix中,将遵循您可以执行的相同逻辑:
perl -wpe "$/='/end CHECK';s/^.*?(Var_\S+).*?(ADDRESS \S+).*$/$1 => $2\n/s" "your_file.txt">"new.txt
首先,我们将结束行字符设置为$/=“/end CHECK”。
然后,我们只选择第一个Var\uu
while ( <$in> )
perl -wpe "$/='/end CHECK';s/^.*?(Var_\S+).*?(ADDRESS \S+).*$/$1 => $2\n/s" "your_file.txt">"new.txt