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