簡體   English   中英

Perl正則表達式變量和匹配的模式替換

[英]Perl regular expression variables and matched pattern substitution

當正則表達式保存在變量中時,有人可以解釋正則表達式文本替換嗎? 我正在嘗試處理一些文本(實際上是Clearcase配置規范),並在替換文本時使用。 替換規則保存在具有正則表達式要匹配且文本要替換的哈希數組中。

輸入文本看起來像這樣:

element  /my_elem/releases/...  VERSION_STRING.020 -nocheckout

大多數替換只是刪除包含特定文本字符串的行,這很好用。 在某些情況下,我想替換文本,但重新使用VERSION_STRING文本。 我試過在替換表達式中使用$ 1,但是它不起作用。 $ 1在比賽中獲取版本字符串,但是替換$ 1在替換中不起作用。

在這些情況下,輸出應如下所示:

element  -directory  /my_elem/releases/... VERSION_STRING.020 -nocheckout
element  /my_elem/releases/.../*.[ch]  VERSION_STRING.020 -nocheckout

即。 一行輸入變成了兩個輸出,並且版本字符串已被重新使用。

該代碼看起來像這樣。 首先是正則表達式和替換:

my @Special_Regex = (   
                  { regex => "\\s*element\\s*\/my_elem_removed\\s*\/main\/\\d+\$",                  subs => "# Line removed" },
                  { regex => "\\s*element\\s*\/my_elem_changed\/releases\/\.\.\.\\s*\(\.\*\$\)", 
                    subs => "element  \-directory  \/my_elem\/releases\/\.\.\. \\1\nelement  \/my_elem\/releases\/\.\.\.\/\*\.\[ch\]  \\1" }

                );

在第二個正則表達式中,變量$ 1在(。* \\ $)部分中定義,並且工作正常。 subs表達式不能替代它。

 foreach my $line (<INFILE>)
        {
        chomp($line);
        my $test = $line;
        foreach my $hash (@Special_Regex)
        {
            my $regex = qr/$hash->{regex}/is;
            if($test =~ s/$regex/$hash->{subs}/)
                {
                print "$test\n";
                print "$line\n";
                print "$1\n";
                }
         }
}

我想念什么? 提前致謝。

正則表達式中的替換字符串僅被評估一次,這會將$hash->{subs}轉換為其字符串。 您需要再次對其求值以對其內部變量進行插值。 您可以在正則表達式的末尾添加e修飾符,該修飾符告訴Perl通過eval運行替代, eval可以執行第二次插值。 您可以應用多個e標志進行多次評估(如果您有需要的話)。 正如tchrist有用地指出的那樣,在這種情況下,您需要ee因為第一個eval只會擴展變量,而第二個eval則需要擴展擴展中的變量。

您可以在perlop找到有關s運算符的更多詳細信息。

沒有用於替換表達式的編譯。 因此,您唯一可以做的就是exec或使用e標志對其進行評估:

if($test =~ s/$regex/eval qq["$hash->{subs}"]/e ) { #...

在替換字符串中將\\\\1更改為\\$1后為我工作。

s/$regex/$hash->{subs}/

僅將匹配的部分替換為$hash->{subs}存儲的文字作為完整替換。 為了使替換生效,您必須強制Perl將字符串評估為string ,因此這意味着您甚至必須重新添加dquotes才能獲得所需的插值行為(因為它們不是一部分)的字符串。)

但這有點笨拙,因此我將replace表達式更改為subs:

my @Special_Regex 
    = ( 
        { regex => qr{\s*element\s+/my_elem_removed\s*/main/\d+$}
        , subs  => sub { '#Line removed' }
        }
    ,   { regex => qr{\s*element\s+/my_elem_changed/releases/\.\.\.\s*(.*$)}
        , subs  => sub { 
            return "element  -directory  /my_elem/releases/... $1\n"
                 . "element  /my_elem/releases/.../*.[ch]  $1"
                 ; 
          }
        }

    );

我擺脫了一堆您不必在替換表達式中轉義的東西。 由於您要執行的操作是將$1的值插值到替換字符串中,因此子例程可以簡單地做到這一點。 而且由於$1在匹配其他內容之前是可見的,因此在運行此代碼時它將是正確的值。

所以現在替換看起來像:

s/$regex/$hash->{subs}->()/e

當然,使它通過 $1會使它更加防彈,因為您不必依賴全局$1

s/$regex/$hash->{subs}->( $1 )/e

當然,您可以這樣更改子代碼:

subs => sub {
    my $c1 = shift;
    return "element  -directory  /my_elem/releases/... $c1\n"
         . "element  /my_elem/releases/.../*.[ch]  $c1"
         ; 
}

最后一個注釋: "\\.\\.\\." 沒有按照您的想法做。 您剛在正則表達式中以'...'結尾,該匹配任何三個字符。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM