2011-11-15 183 views
0

我一直無法弄清楚如何處理特定的正則表達式問題。Perl正則表達式替換

說我有一個很大的字符串,由方括號中的很多短語組成。短語標籤(例如SVP),令牌(例如wwSf),該令牌旁邊的斜線,然後是令牌的描述(例如CCVBD_MS3)。

所以這裏是一個例子字符串:

[S w#/CC] [VP mSf/VBD_MS3] 

我想刪除整個第一括號內的短語,把W的這裏面有第二句話,就像這樣:

[VP wmSf/VBD_MS3] 

是這樣甚至可能使用正則表達式?


編輯: 好的圖案是:

[ <label> w#/<label>] [<label> <word>/<label> <word>/<label> <word>/<label>...] 

(第二方括號內的短語可以有一個到任意數量的/雙)

其中可以是大寫字母的任何序列,其可能包含一個下劃線,而單詞可以是任何不是空白的序列(即數字/字符/特殊字符)。

+0

你提到很多短語,你可以給你的目標的普通描述,而不是兩個短語的例子 – SAN

+0

散列符號是否真的是第一個短語的一部分?說明中沒有提及它。 – choroba

+0

是的,散列是該短語的一部分。但是當我在第二個短語中附加w時,我不需要它。 – user961627

回答

1

不知道實際的形式或位置,這些形式之一可能工作(未經測試):

s{\[S (\w+)#/\w+\] (\[VP)(\w+/\w+\])}{$2$1$3}g

s{\[(?:S/VP) (\w+)#/\w+\] (\[(?:S/VP))(\w+/\w+\])}{$2$1$3}g

s{\[(?:S/VP)\s+(\w+)#/\w+\]\s+(\[(?:S/VP)\s+)(\w+/\w+\])}{$2$1$3}g

編輯 由於您的修改已列入這種模式
[ <label> w#/<label>] [<label> <word>/<label> <word>/<label> <word>/<label>...]
它可以更容易地拿出一個正則表達式,應該工作。

祝你好運!

use strict; 
use warnings; 


$/ = undef; 

my $data = <DATA>; 


my $regex = qr{ 

     \[\s*       #= Start of token phrase '[' 
      (?&label) \s+     # <label> then whitespace's 
      ((?&word))     # Capture $1 - token word, end grp $1 
      [#]/(?&label)     # '#'/<label> 
      \s* 
     \]       #= End of token phrase ']' 
     \s* 
    (       # Capture grp $2 
     \[\s*       #= Start of normal phrase '[' 
      (?&label) \s+     # <label> then whitespace's 
    )        # End grp $2 
    (       # Capture grp $3 
      (?&word)/(?&label)   # First <word>/<label> pair 
      (?:      
      \s+(?&word)/(?&label)  # Optional, many <word>/<label> pair's 
     )*      
      \s* 
     \]       #= End of normal phrase ']' 
    )        # End grp $3 

    (?(DEFINE)    ## DEFINE's: 
    (?<label> \w+)    # <label> - 1 or more word characters 
    (?<word> [^\s\[\]]+)  # <word> - 1 or more NOT whitespace, '[' nor ']' 
    ) 
}x; 


$data =~ s/$regex/$2$1$3/g; 

print $data; 

__DATA__ 

[S w#/CC] [VP mSf/VBD_MS3] 

輸出:
[VP wmSf/VBD_MS3]

EDIT2
「如果字符的標籤是PP,如果下一個樂句的標籤是NP,然後更改下一個樂句的標籤,PP以及當輸入:[PP w#/ IN] [NP something/NN]輸出:[PP wsomething/NN]「

當然,如果不添加太多的新捕獲組,它可以通過回調。
其實,有很多方法可以做到這一點,包括正則表達式條件。我認爲最簡單的方法是回調,其中可以進行所有標籤決策的邏輯。

use strict; 
use warnings; 


$/ = undef; 

my $data = <DATA>; 


my $regex = qr{ 

    (\[\s*     # 1 - Token phrase label 
     (?&label)   
     \s+ 
    ) 
     (     # 2 - Token word 
      (?&word) 
     )   
     [#]/(?&label) 
     \s* 
    \] 
    \s* 

    (\[\s*     # 3 - Normal phrase label 
     (?&label) 
     \s+ 
    ) 
     # insert token word ($2) here 
    (      # 4 - The rest .. 
     (?&word)/(?&label) 
     (?: \s+ (?&word)/(?&label))*      
     \s* 
     \] 
    ) 

    (?(DEFINE)    ## DEFINE's: 
    (?<label> \w+)    # <label> - 1 or more word characters 
    (?<word> [^\s\[\]]+)  # <word> - 1 or more NOT whitespace, '[' nor ']' 
    ) 
}x; 


$data =~ s/$regex/ checkLabel($1,$3) ."$2$4"/eg; 


sub checkLabel 
{ 
    my ($p1, $p2) = @_; 
    if ($p1 =~ /\[\s*PP\s/ && $p2 =~ /(\[\s*)NP(\s)/) { 
     return $1.'PP'.$2; 
     # To use the formatting of the token label, just 'return $p1;' 
    } 
    return $p2; 
} 


print $data; 

__DATA__ 

[PP w#/CC] [ NP  mSf/VBD_MS3] 
+0

謝謝@sln,這段代碼真的幫助我更多地瞭解正則表達式! 我修改了此頁面上的幫助,併成功地獲得了我需要的所有內容,除了一個問題。 是否可以執行以下操作: - 始終將#之前的字符連接到下一個短語BUT - 如果字符的標籤爲PP,並且下一個短語的標籤爲NP,則將下一個短語的標籤更改爲PP以及加入時。 例如。輸入:[PP w#/ IN] [NP something/NN] 輸出:[PP wsomething/NN] < - 所以在這種情況下,第二個短語的標籤已從NP更改爲PP。 – user961627

+0

沒問題,補充** Edit2 **。 – sln

1

是,

s|\[S w#/CC\] \[(VP) (mSf/VBD_MS3)\]|[$1 w$2]|; 

現在什麼模式你找誰?

你甚至可以這樣做:

s|\[S (w)#/CC\] \[(VP) (mSf/VBD_MS3)\]|[$2 $1$3]|; 
+0

我覺得你沒有捕捉到w,不應該是 s | \ [S(w#)/ CC \] \ [(VP)(mSf/VBD_MS3)\] | [$ 2 $ 1 $ 3] |;'' – SAN

+0

好吧,我很困惑......應該不是「s/string/replacent/g」嗎?數字意味着什麼? $ 1,$ 2等?我一直在使用基本的正則表達式一段時間,但當涉及到這個東西,我不明白它,我已經嘗試過教程.. – user961627

+0

嗨Axeman謝謝你的幫助。我編輯了問題並添加了模式。 – user961627

0
#/usr/bin/env perl 
use strict; 
use warnings; 
my $str = "[S w#/CC] [VP mSf/VBD_MS3]"; 
$str =~ s{\[S w#/CC\]\s*(\[VP\s)(.+)}{$1w$2} and print $str; 
+0

你能編輯你的答案來提供一些上下文和解釋嗎? – Gray

1

而不是創建一個神奇的正則表達式來完成整個工作,爲什麼不把線分成短語,對它們進行操作然後返回它們。然後,遵循您剛剛解釋的相同邏輯。

這樣乾淨,更具可讀性(尤其是如果添加註釋的話)和健壯性。當然,您需要根據自己的需要量身定製:例如,您可能希望將/分隔的部分轉換爲鍵/值對(如果不製作hashref,那麼順序是否重要?如果你不需要修改標籤,也許你不需要拆分/;等

每評論

編輯: 這需要一個#之前字面w,將其存儲,刪除這句話,然後大頭針的w到下一個樂句。如果那就是你所需要的。當然,我確定有一些邊緣案例需要注意,所以先備份和測試!

#!/usr/bin/env perl 

use strict; 
use warnings; 

while(my $line = <DATA>) { 
    #separate phrases, then split phases into whitespace separated pieces 
    my @phrases = map { [split /[\s]/] } ($line =~ /\[([^]]+)\]/g); 

    my $holder; # holder for 'w' (not really needed if always 'w') 
    foreach my $p (@phrases) { # for each phrase 
    if ($p->[1] =~ /(w)#/) { # if the second part has 'w#' 
     $holder = $1; # keep the 'w' in holder 
     $p = undef; #empty to mark for cleaning later 
     next; #move to next phrase 
    } 

    if ($holder) { #if the holder is not empty 
     $p->[1] = $holder . $p->[1]; # add the contents of the holder to the second part of this phrase 
     $holder = undef; # and then empty the holder 
    } 
    } 

    #remove emptied phrases 
    @phrases = grep { $_ } @phrases; 

    #reconstitute the line 
    print join(' ', map { '[' . join(' ', @$_) . ']' } @phrases), "\n"; 
} 

__DATA__ 
[S w#/CC] [VP mSf/VBD_MS3] 

再次,它可能看起來令人驚奇,你可以用一個正則表達式做什麼,但如果你的老闆進來說,「你知道會發生什麼,你寫做X偉大工程的那個東西,但現在它需要也要做Y「。這就是爲什麼我喜歡爲每個邏輯步驟保留好邏輯的原因。

+0

謝謝,這工作。但是,它將所有以下短語分配爲最初的「w」。不是緊隨其後的那個短語。我們如何添加該約束? (因爲這個代碼有點超出我:() – user961627

+0

爲了讓它完全正確,如果它有'#'或者它有'S'(哪一個?),然後粘性'#'到下一個項目之前的字符? –

+0

是的,沒錯,我想刪除的短語是一個有aw的標籤,但標籤可能是S或其他任何東西 – user961627