Perl: хорошо это или плохо, и как его улучшить? - PullRequest
6 голосов
/ 29 мая 2011

Я пытаюсь зафиксировать выходную температуру датчиков, для которых у меня есть следующие соответствующие строки:

temp1:       +39.5 C  (crit = +105.0 C)
Core 0:      +40.0 C  (high = +100.0 C, crit = +100.0 C)
Core 1:      +40.0 C  (high = +100.0 C, crit = +100.0 C)

Мне нужна только первая температура каждой линии (39,5, 40,0, 40,0).Конечно, проблема в том, что я не могу сказать слово «номер», так как в «Core 0» / «Core 1» есть дополнительный пробел.

Я пришел к следующему регулярному выражению, которое работает,однако мне сказали, что использование .* является несколько ленивым и грязным подходом к регулярным выражениям.

$core_data =~ s/^.*\+(.*)C\ .*$/$1/g;

Мне было интересно, есть ли более надежный или лучший способ сделать это или я в порядке

Ответы [ 6 ]

6 голосов
/ 29 мая 2011

Более краткое регулярное выражение

/\+(\d+\.?\d*) C/

, которое будет соответствовать первой температуре с необязательным десятичным значением.

#!/usr/bin/perl
use strict;
use warnings;

my $re = qr{\+(\d+\.?\d*) C};
while (my $line = <DATA>){
    $line =~$re and print $1,"\n";
}
__DATA__
temp1:       +39.5 C  (crit = +105.0 C)
Core 0:      +40.0 C  (high = +100.0 C, crit = +100.0 C)
Core 1:      +40.0 C  (high = +100.0 C, crit = +100.0 C)

вывод:

39.5
40.0
40.0
3 голосов
/ 29 мая 2011

Я не понимаю, почему вы делаете поиск и заменяете своим регулярным выражением (s///g), если вы просто пытаетесь измерить первую температуру. Ваше регулярное выражение, похоже, полагается на то, что .* является жадным. Предполагая, что вы можете положиться на формат name: temp C (..., это регулярное выражение будет работать без совпадения всей строки:

$core_data =~ m/^(?:\w*\b)*:\s*(\+?\d+\.\d+)/;

... или захватить без + перед:

$core_data =~ m/^(?:\w*\b)*:\s*\+?(\d+\.\d+)/;
2 голосов
/ 29 мая 2011

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

my $tag;
($tag, $core_data) = split (/:/, $core_data);
my @fields = split (/\s/, $core_data);
my $temp   = $fields[0];

Это будет хранить строки "+39.5" и "+40.0" в разныхя полагаю, что примеры строк, которые могут быть автоматически преобразованы в число.

Кроме того, у вас будет легкий доступ к метке строки в $tag.

Если вы хотите, выможно отрубить добавленную информацию в скобках с помощью регулярного выражения:

if ($core_data =~ s/\(([^\)]*)\)//) {
    my $tmp = $1;
    $tmp =~ s/[\s\+C]//g; # clear away junk
    %data = split (/=/, (split (/,/, $tmp)));
}
for my $key (keys %data) {
    printf "%-7s = %s\n", $key, $data{$key};
}
2 голосов
/ 29 мая 2011

ИМХО. * Прекрасно, когда в этом есть смысл, хотя, когда вы можете сузить его до чего-то более конкретного, тогда все будет лучше.

В вашем случае вы могли бы сказать

S/^[^+]+\+([0-9.]) C.*$/$1/g

В этом регулярном выражении я сосредотачиваюсь на том, что ищу, и характеризую температуру как последовательность цифр с точкой где-то, в то время как остальное просто не имеет отношения к мне.Поскольку у вас есть две температуры в каждой строке, и вы хотите только первую, я использовал [^ +] в начале, который соответствует всему, что не является +, поэтому он остановится там, где начинается первая температура.Получив температуру, я сожрал все, используя. * до конца строки.

Это всего лишь пример рассуждений, он не претендует на то, чтобы быть лучшим регулярным выражением, с которым вы можете придуматьрешить вашу проблему.

2 голосов
/ 29 мая 2011

Более точное регулярное выражение

 $core_data =~ s/^.*\+([\d.]+ )C\ .*$/$1/g;

Но, вероятно, следующего достаточно, потому что интересным представляется только числовое значение.

 $cpu_head = $1 if m/:\s*\+([\d.]+) C/;

Примечание: \ s означает любой пробел, а \ d - любую цифру.

1 голос
/ 30 мая 2011

Я бы написал общую функцию, которая анализирует входные данные и возвращает вам хэш. В общем, я бы использовал это регулярное выражение:

m/\A ([^:]+) : \s+ ([+-][0-9.]+) /xms

Это соответствует строке. В $ 1 это то, что соответствует (то есть: «Ядро 0»), а в $ 2 - температура. Я также сделал бы преобразование из строки в число, которое закончилось бы чем-то вроде этого:

my $temp_string = q{
temp1:       +39.5 C  (crit = +105.0 C)
Core 0:      +40.0 C  (high = +100.0 C, crit = +100.0 C)
Core 1:      +40.0 C  (high = +100.0 C, crit = +100.0 C)
Core 2:      -40.0 C  (high = +100.0 C, crit = +100.0 C)
};

my $temps = parse_temps($temp_string);

print "temp1:  ", $temps->{temp1}, "\n";
print "Core 0: ", $temps->{core0}, "\n";
print "Core 1: ", $temps->{core1}, "\n";
print "Core 2: ", $temps->{core2}, "\n";


sub parse_temps {
    my ( $str ) = @_;
    my %temp;
    for my $line ( split /\n/, $str ) {
        if ( $line =~ m/\A ([^:]+) : \s+ ([+-][0-9.]+) /xms ) {
            my $key   = $1;
            my $value = $2;

            $key   =~ s/\s+//g;
            $temp{ lc $key } = 0+$value;
        }
    }
    return wantarray ? %temp : \%temp;
}

Вывод программы:

temp1:  39.5
Core 0: 40
Core 1: 40
Core 2: -40
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...