2009-11-15 64 views
2

Perl中,如何從當前位置(最後一個替換位置)替換一個模式直到行尾?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. 
+0

請舉例說明您正在執行這些操作的輸入。 – 2009-11-15 12:43:55

+0

這是一個Web服務器日誌行,我沒有在我的代碼示例中包含所有替換項。 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)「 – Lucia 2009-11-15 13:12:45

回答

-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]包含之前的位置的更換。所以也許有更好的辦法:)

+3

將OP更好地替換這個序列的'/'操作會好得多「使用getMonth'返回的內容替換方括號中的月份+年份),並使用更簡潔的操作,並允許其餘的需求得到滿足。但是,這需要OP的合作。 – 2009-11-15 13:02:09

+1

**'** + ** **是**不是**數組。 **'@ +'**是。我糾正了你的錯誤,並將其鏈接到文檔中的正確位置。回滾那些實際的更正(您可以輕鬆驗證)是不正確的。 http://perldoc.perl.org/perlvar.html#%40%2b – 2009-11-15 13:43:21

+0

@SinanÜnür:如果你添加評論,我可以編輯我的答案,如果我同意(在這裏完成) – Andomar 2009-11-15 15:10:24

8

我看你接受了一個答案。然而,對於手頭的任務,那將是更適合使用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

從你的語言,你似乎想象你的替換序列正在向前穿過字符串,每個替換佔據最後一個替換的地方。實際上,每個替代將適用於整個字符串。

當你說「最後一次替換的位置」時,如果前面的替換沒有發現,會發生什麼?

在腳本中,你可以做:

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

但使用$應該在可重用的代碼來避免」,因爲它可能會影響其他正則表達式的性能。在那裏,你需要做的

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

但在這兩種情況下,你需要確保你所期望的匹配或替換已經設置$」或@ +真正成功。

+0

「this」是最後一個替換的位置,其中'\ s \ + \ d \ d \ d \ d \ d'匹配。如果你知道比'$ + [0]'更好的方式,請發佈:) – Andomar 2009-11-15 19:54:55

+1

@Andomar:對不起,沒有足夠好的閱讀這個問題;完全替換了我的答案 – ysth 2009-11-15 19:56:54

+0

+1's /。*/+ /'應該是's// +/g',但很高興看到substr上的替換改變了原始字符串 – Andomar 2009-11-15 20:07:57