【问题标题】:Perl - Searching values in a log file and store/print them as a string.Perl - 在日志文件中搜索值并将它们存储/打印为字符串。
【发布时间】:2017-07-07 10:27:49
【问题描述】:

我想在日志文件中的特定单词 (Current Value = ) 之后搜索值,并创建一个带有值的字符串。

vcs_output.log:一个日志文件

** Fault injection **
  Count = 1533
  0: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rcc_data_e[6]
  0: Current value = x
  1: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs3_data_e[51]
  1: Current value = x
  2: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs1_data_e[3]
  2: Current value = 1
  3: Path = cmp_top.iop.sparc0.exu.alu.shft_alu_shift_out_e[18]
  3: Current value = 0
  4: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs3_data_e[17]
  4: Current value = x
  5: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs1_data_e[43]
  5: Current value = 0
  6: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rcc_data_e[38]
  6: Current value = x
  7: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs2_data_e_l[30]
  7: Current value = 1
   .
   .
   .

如果我在“当前值 =”之后存储值,则为 x,x,1,0,x,0,x,1。我最终将它们保存/打印为字符串,例如 xx10x0x1。

这是我的代码 代码.pl:

#!/usr/bin/perl 

use strict;
use warnings;
##### Read input
open ( my $input_fh, '<', 'vcs_output.log' ) or die $!; 
chomp ( my @input = <$input_fh> );

my $i=0;
my @arr;
while (@input) {
    if (/Current value = /)
    $arr[i]= $input;  # put the matched value to array 
   }

}

## make a string from the array using an additional loop 

close ( $input_fh );

我认为有一种方法可以在一个循环中创建一个字符串(甚至不使用循环)。请建议我去做。任何建议表示赞赏。

【问题讨论】:

    标签: string perl search


    【解决方案1】:

    你可以做你要求的。

    要直接构建字符串,只需将您在正则表达式中捕获的内容附加到它

    my $string;
    while (<$input_fh>) 
    {
        my ($val) = /Current\s*value\s*=\s*(.*)/;
        $string .= $val;
    }
    

    如果匹配失败,那么$val 是一个空字符串,所以我们不必测试。你也可以将整个while循环写在一行中

    $string .= (/Current\s*value\s*=\s*(.*)/)[0] while <$input_fh>;
    

    但我不明白为什么有必要这样做。请注意,这是从文件句柄中逐行读取的。没有理由首先将所有行读入数组。


    为了避免(显式)循环,您可以读取所有行并将它们通过map,天真地作为

    my $string = join '', 
        map { (/Current\s*value\s*=\s*(.*)/) ? $1 : () } <$input_fh>;
    

    由于map 需要一个列表,文件句柄在列表上下文中,返回文件中所有行的列表。然后每个都被map的块中的代码处理,然后加入它的输出列表。

    技巧map { ($test) ? $val : () } 使用map 来完成grep 的工作,过滤——如果$test 失败返回的空列表被展平到输出列表中,从而消失。这里的“测试”是正则表达式匹配,在标量上下文中返回真/假,而捕获集$1

    但是,和上面一样,我们可以返回匹配返回的列表的第一个元素,而不是测试匹配是否成功。由于我们在map,我们实际上可以返回“整个”列表

    my $string = join '', 
        map { /Current\s*value\s*=\s*(.*)/ } <$input_fh>;
    

    这里可能更清楚。


    对问题中代码的评论

    • while (@input) 是一个无限循环,因为@input 永远不会耗尽。你需要foreach (@input)——但最好只阅读文件句柄while (&lt;$input_fh&gt;)

    • 您的正则表达式确实与该字符串在一行上匹配,但它不会尝试匹配您需要的模式(= 后面的内容)。添加后,它也需要被 ()

    • 捕获
    • 你可以分配给第 i 个元素(应该是 $i),但是你必须在你去的时候增加 $i。大多数时候最好只push @array, $value

    【讨论】:

    • 你不需要条件表达式。 my $string = join '', map { /Current\s*value\s*=\s*(\S+)/ } &lt;$input_fh&gt; 可以正常工作,因为不匹配的正则表达式会在列表上下文中返回一个空列表。
    • @Borodin 是的,我认为我已经拥有了(map 的第二个示例)——我还想展示如何在map 中使用条件,因为它会派上用场.但是您的评论让我意识到我只使用了元素,map 不需要(更新)。谢谢。
    • @JaeyoungPark 你能解释一下“比特”是什么意思吗?您正在从文件中读取,每个 0,1,x 都是 characters - 每个(至少)一个字节。您的意思是将字符串拆分为 3-3-2 个字符块吗?或者将您的 8 符号结果视为一个字节,对每个位编码 0,1,x 之一,并将其​​拆分为 3-3-2 位? (这可能需要其他澄清,最好单独提出。)那么x 是什么意思?
    • @zdim,在我的情况下,每个字符都有点。我正在从日志文件中读取二进制位。 0 或 1,x 是无关位,因此它可以是 0 或 1。日志文件中有 8 行(和值),我想创建三个字符串,例如 xx1、0x0 和 x1
    • @JaeyoungPark 等等,让我们澄清一下。您显示一个ascii文件,并正常读取它,文件中的10分别存储在一个字符中。不是一点点,而是(可能)一个字节。正如您在问题中所说,对于所有这些,您都会得到“字符串,例如xx10x0x1”。代码清楚地将它们放在一个字符串中,其中每个都是一个字符(这就是我的意思)。现在,假设您需要01,您可以 用一位来表示它们。这是你想要的,将它们转换成比特吗?
    【解决方案2】:

    你可以使用捕获括号来抓取你想要的字符串:

    use strict;
    use warnings;
    
    my @arr;
    open ( my $input_fh, '<', 'vcs_output.log' ) or die $!; 
    while (<$input_fh>) {
        if (/Current value = (.)/) {
            push @arr, $1;
        }
    }
    close ( $input_fh );
    print "@arr\n";
    
    __END__
    
    x x 1 0 x 0 x 1
    

    【讨论】:

      【解决方案3】:

      使用grepperlre
      http://perldoc.perl.org/functions/grep.html
      http://perldoc.perl.org/perlre.html

      如果在非 Unix 环境中,那么...

      #!/usr/bin/perl -w
      use strict;
      
      open (my $fh, '<', "vcs_output.log");
      
      chomp (my @lines = <$fh>);
      
      # Filter for lines which contain string 'Current value'
      @lines = grep{/Current value/} @lines;
      
      # Substitute out what we don't want... leaving us with the 'xx10x0x1'
      @lines = map { $_ =~ s/.*Current value = //;$_} @lines;
      my $str = join('', @lines);
      
      print $str;
      

      否则……

      #!/usr/bin/perl -w
      use strict;
      
      my $output = `grep "Current value" vcs_output.log | sed 's/.*Current value = //'`;
      
      $output =~ s/\n//g;
      print $output;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多