2017-02-17 11 views
-1

Я хотел бы найти значения после определенного слова (Текущее значение =) в файле журнала и создать строку со значениями.Perl - поиск значений в файле журнала и сохранение/печать их в виде строки.

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 
    . 
    . 
    . 

Если хранить значения после того, как "Текущее значение =", то х, х, 1,0, х, 0, х, 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

Вы можете сделать так, что вы просите.

Чтобы построить строку непосредственно, просто добавьте к нему то, что вы захватить в регулярном выражении

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 «s работа, для фильтрации - пустой список, который возвращается, если $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, как вы идете. Большую часть времени, то лучше всего push @array, $value

+0

Вам не нужно условное выражение. 'my $ string = join '', map {/ Current \ s * value \ s * = \ s * (\ S +) /} <$input_fh>' будет работать нормально, потому что несогласованное регулярное выражение возвращает пустой список в контексте списка. – Borodin

+0

@Borodin Да, у меня было, что я думаю (второй пример с 'map') - я хотел также показать, как использовать условие в' map', когда это пригодится. Но ваш комментарий заставило меня понять, что я беру только элемент, который в «карте» не нужен (обновляется). Спасибо. – zdim

+0

@JaeyoungPark Можете ли вы объяснить, что вы подразумеваете под «битами»? Вы читаете из файла, и каждый из них «0,1, x» являются _characters_ - байтом каждый (по крайней мере). Вы хотите разбить строку на 3-3-2 символа? Или считать свой 8-символьный результат байтом, кодируя один из «0,1, x» за бит и разбивая его на 3-3-2 бита? (Для этого могут потребоваться другие разъяснения, и это может быть лучше спрошено отдельно.) Что означает «х»? – zdim

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 
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;