English 中文(简体)
Perl: replace pattern from the current position until the end of a line
原标题:

In Perl, how can I replace a pattern from the current position (the position of the last replacement) until the end of a line?

I have done all of these replacements in a single line:

...
s/[//;
s/(/www/)/ getMonth $1 /e;
s/:/ /;
s/s+dddd]//;
#NOW: replace all blanks with a plus sign from this position until the end of this line.
问题回答

I see you have accepted an answer. However, for the task at hand, it would have been more appropriate to use Apache::ParseLog or maybe Apache::LogRegex:

Apache::LogRegex - Parse a line from an Apache logfile into a hash

It looks to me like you are trying to write a log file analyzer from scratch and this is your way of grouping log file entries by month. If that is the case, please stop re-inventing square wheels.

Even if you do not want to use external modules, you can simplify the task by dividing and conquering using 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), "
";

Output:

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)"

From your language, you seem to be imagining your sequence of substitutions are working forward through the string, each substitution taking up where the last one left off. In fact, each substitution will apply to the entire string.

When you say "the position of the last replacement", what should happen if the previous substitution found nothing?

In a script, you can just do:

if ( s/s+dddd]// ) { $  =~ s/ /+/g }

but use of $ should be avoided in reusable code, since it can impact performance of other regular expressions. There, you d need to do

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

but in either case, you need to make sure that the match or substitution you expect to have set $ or @+ actually succeeded.





相关问题
Why does my chdir to a filehandle not work in Perl?

When I try a "chdir" with a filehandle as argument, "chdir" returns 0 and a pwd returns still the same directory. Should that be so? I tried this, because in the documentation to chdir I found: "...

How do I use GetOptions to get the default argument?

I ve read the doc for GetOptions but I can t seem to find what I need... (maybe I am blind) What I want to do is to parse command line like this myperlscript.pl -mode [sth] [inputfile] I can use ...

Object-Oriented Perl constructor syntax and named parameters

I m a little confused about what is going on in Perl constructors. I found these two examples perldoc perlbot. package Foo; #In Perl, the constructor is just a subroutine called new. sub new { #I ...

Where can I find object-oriented Perl tutorials? [closed]

A Google search yields a number of results - but which ones are the best? The Perl site appears to contain two - perlboot and perltoot. I m reading these now, but what else is out there? Note: I ve ...

热门标签