2013-07-01 166 views
1

如何匹配下一行?Perl正則表達式與LHS組合

sometext_TEXT1.yyy-TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 

想要從最後刪除- repetative.text,但只有當它重複。

sometext_TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 

我試圖

use strictures; 
my $text="sometext_TEXT1.xxx-TEXT1.xxx"; 
$text =~ s/(.*?)(.*)(\s*-\s*$2)/$1$2/; 
print "$text\n"; 

打印

Use of uninitialized value $2 in regexp compilation at a line 3. 

與其他詞,尋找下一個split + match更好的解決方案...

while(<DATA>) { 
     chomp; 

     my($first, $second) = split /\s*-\s*/; 
     s/\s*-\s*$second$// if ($first =~ /$second$/); 

     print "$_\n"; 
} 
__DATA__ 
sometext_TEXT1.yyy-TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 
+4

在替代的匹配部分反向引用必須\ 2而不是$ 2 – user1937198

回答

2
$text =~ s/(.*?)(.*)(\s*-\s*$2)/$1$2/; 

這個正則表達式有不同的問題,但在正確的道路上。

  1. 使用\2(或更好:\g2\g{-1})或東西來引用捕獲組的內容。在執行Perl語句時插入$2變量。那時,$2是未定義的,因爲之前沒有匹配。由於未初始化,您會收到警告。即使它被定義,模式在編譯期間也會被修復。

  2. 你定義了三個捕獲組,但只需要一個。有一個與\K EEP指令一招:它讓我們的正則表達式引擎忘記先前匹配的文本,所以它不會被替代的影響。也就是說,s/(foo)b/$1/相當於s/foo\Kb//。效果類似於可變長度lookbehind。

  3. (.*?)(.*)的部分是一個位的回溯夢魘。我們可以通過添加更多條件來降低您的匹配成本。通過錨定模式開始和結束的行。使用上述修改,我們現在有s/^.*?(.*)\K\s*-\s*\g1$//。但轉念一想,我們可以只取出^.*?因爲這說明什麼正則表達式引擎做呢!

一個簡短的測試:

while(<DATA>) { 
    s/(.*)\K\s*-\s*\g1$//; 
    print; 
} 
__DATA__ 
sometext_TEXT1.yyy-TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 

輸出:

sometext_TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 

的幾句話對您split亭解決方案:這也將縮短線路

sometext_TEXT1xyyy - 1.xyyy 

因爲當你插入一個變量到一個正則表達式中時,內容不會逐字匹配。相反,它們被解釋爲一種模式(其中.與任何非新行代碼點匹配)!您可以通過引用所有的元字符與\Q...\E逃生避免這種情況:

s/\s*-\s*\Q$second\E$// if $first =~ /\Q$second\E$/; 
1

當您使用$2 Perl將嘗試插入該變量,但該變量只會在匹配完成後設置爲。你想要的,什麼是反向引用,爲此,你需要使用\2

$text =~ s/(.*?)(.*)(\s*-\s*\2)/$1$2/; 

需要注意的是,當更換部件進行評估,$1$2已定,預期可以插值。你也可以將圖案多一點簡潔(而且可能更有效),使用:

$text =~ s/(.*)\s*-\s*\2/$1/; 

沒有必要的初始部分(.*?)相匹配,如果是任意的,你只是把它寫回無妨。你可能希望做雖然是錨定模式字符串的結尾:

$text =~ s/(.*)\s*-\s*\1$/$1/; 

否則(你的初次嘗試或地雷),你會轉something-thingelsesomethingelse

+0

最後的正則表達式應該是'$文字=〜S /(。 *)\ s * - \ s * \ 1 $/$ 1 /;'...... :) – jm666

+0

@ jm666當然!謝謝!修正 –