Perl:将模式从当前位置替换为一行

时间:2009-11-15 12:24:05

标签: regex perl replace

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 个答案:

答案 0 :(得分:8)

我看到你已经接受了答案。但是,对于手头的任务,使用Apache::ParseLogApache::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)"

答案 1 :(得分:2)

从您的语言来看,您似乎在想象您的替换序列正在通过字符串向前发展,每次替换都会占用最后一个替换的位置。实际上,每个替换都将应用于整个字符串。

当你说“最后一次替换的位置”时,如果之前的替换没有找到什么会发生什么?

在脚本中,你可以这样做:

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

但在可重用代码中应避免使用$',因为它会影响其他正则表达式的性能。在那里,你需要做

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

但在任何一种情况下,您都需要确保您希望设置$'或@ +的匹配或替换实际上已成功。

答案 2 :(得分:-3)

从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]包含替换之前的位置。所以也许有更好的方法:)