Perl: заменить шаблон с текущей позиции до конца строки - PullRequest
2 голосов
/ 15 ноября 2009

В Perl , как я могу заменить шаблон с текущей позиции (позиции последней замены) до конца строки?

Я сделал все эти замены в одной строке:

...
s/\[//;
s/(\/\w\w\w\/)/ getMonth $1 /e;
s/:/ /;
s/\s\+\d\d\d\d\]//;
#NOW: replace all blanks with a plus sign from this position until the end of this line.

Ответы [ 3 ]

8 голосов
/ 15 ноября 2009

Я вижу, вы приняли ответ. Однако для данной задачи было бы более целесообразно использовать Apache :: ParseLog или, возможно, Apache :: LogRegex :

Apache::LogRegex - Разобрать строку из лог-файла Apache в хеш

Мне кажется, что вы пытаетесь написать анализатор файла журнала с нуля, и это ваш способ группировки записей файла журнала по месяцам. Если это так, пожалуйста, прекратите изобретать квадратные колеса.

Даже если вы не хотите использовать внешние модули, вы можете упростить задачу, разделив и победив, используя split :

#!/usr/bin/perl

use strict; use warnings;
use Carp;
use Regex::PreSuf;

my @months = qw(jan feb mar apr may jun jul aug sep oct nov dec);
my %months = map { $months[$_] => sprintf '%02d', $_ + 1 } 0 .. 11;
my $months_re = presuf( @months );

# wrapped for formatting, does not make any difference
my $str = q{62.174.188.166 - - [01/Mar/2003:00:00:00 +0100] "GET
/puntos/img/ganar.gif HTTP/1.1" 200 1551
"http://www.universia.com/puntos/index.jsp";
"Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 2.0)"};

chomp($str);

my @parts = split qr{\s\[|\]\s}, $str;

if ( $parts[1] =~ m! / ($months_re) / !ix ) {
    $parts[1] = $1;
}

$parts[2] =~ s/\s/+/g;

print join(' ', @parts), "\n";

Выход:

62.174.188.166 - - Mar "GET+/puntos/img/ganar.gif+HTTP/1.1"+200+1551+"http://www .universia.com/puntos/index.jsp";+"Mozilla/4.0+(compatible;+MSIE+5.0;+Windows+98 ;+DigExt;+Hotbar+2.0)"

2 голосов
/ 15 ноября 2009

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

Когда вы говорите «позиция последней замены», что должно произойти, если предыдущая замена ничего не нашла?

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

if ( s/\s\+\d\d\d\d\]// ) { $' =~ s/ /+/g }

но следует избегать использования $ 'в повторно используемом коде, поскольку это может повлиять на производительность других регулярных выражений. Там вам нужно сделать

if ( s/\s\+\d\d\d\d\]// ) { substr($_, $+[0]) =~ s/ /+/g }

но в любом случае вам нужно убедиться, что совпадение или подстановка, которые вы ожидали установить $ 'или @ +, действительно были успешными.

0 голосов
/ 15 ноября 2009

Начиная с Perl 5.6, позиция в конце последнего совпадения сохраняется в массиве @+. Позиция в конце всего матча: $+[0].

Вы можете использовать это, чтобы разбить строку на две части, и сделать замену только на более поздней части:

my $base = " pears apples bananas coconuts ";
$base =~ s/apples/oranges/;
my $firstpart = substr($base, 0, $+[0]);
my $secondpart = substr($base, $+[0]); 
$secondpart =~ s/ /\+/g;
print '"' . $firstpart . $secondpart . "\"\n";

Который напечатает:

" pears oranges+bananas+coconuts+"

Одной из проблем этого подхода является то, что $+[0] содержит позицию перед заменой. Так что, возможно, есть лучший способ:)

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