我想在日志文件中的特定单词(当前值=)之后搜索值,并创建一个包含值的字符串。
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。
这是我的代码 code.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 );
我认为有一种方法可以在一个循环中创建一个字符串(甚至不使用循环)。请指教我做。任何建议表示赞赏。
答案 0 :(得分:1)
您可以使用捕获括号来获取所需的字符串:
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
答案 1 :(得分: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
失败则返回的空列表会变为输出列表,因此消失。这里的“测试”是正则表达式匹配,在标量上下文中返回true / false,而捕获集$1
。
但是,如上所述,我们可以返回匹配返回的列表的第一个元素,而不是测试匹配是否成功。由于我们在map
,我们实际上可以返回“整个”列表
my $string = join '',
map { /Current\s*value\s*=\s*(.*)/ } <$input_fh>;
这里可能更清楚。
对问题中代码的评论
while (@input)
是一个无限循环,因为@input
永远不会耗尽。您需要foreach (@input)
- 但最好只阅读文件句柄,while (<$input_fh>)
你的正则表达式在与该字符串的行上匹配,但它不会尝试匹配您需要的模式(=
后面的内容)。添加后,还需要通过()
你可以分配给第i个元素(应该是$i
),但是你必须随时增加$i
。大多数情况下,只有push @array, $value
答案 2 :(得分:0)
使用grep
和perlre
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;