2012-06-25 105 views
2

我正在將一個SMAPI文法轉換爲JSGF。它們是用於不同語音識別系統的相當類似的語法。 SMAPI使用他們世界其他地方所用的問號來表示0或1。 JSGF爲此使用方括號。所以,我需要將像stuff?這樣的字符串轉換爲[stuff],並將括號內的字符串如((((stuff)? that)? I)? like)?改爲[[[[stuff] that] I] like]。我必須獨自留下像((((stuff) that) I) hate)這樣的字符串。正如Qtax指出的,更復雜的例子是(foo ((bar)? (baz))?)(foo [[bar] (baz)])取代。提取每一級括號的內容

因此,我必須提取每個級別的括號表達式,看它是否以問號結尾,並用方括號代替parens和問號(如果有的話)。 我認爲埃裏克斯特羅姆的回答this問題幾乎是我需要的。問題是,當我使用它時,它會返回最大的匹配分組,而我需要對每個分組進行操作。

這是我到目前爲止:s/(\((?: [^()?]* | (?0))* \)) \?/[$1]/xg。但是,如果與((((stuff)? that)? I)? like)?匹配,則僅生成[((((stuff)? that)? I)? like)]。任何想法如何做到這一點?

+3

而不是正則表達式,你可以用一個字符串替換用''''替換'('用'''和')?'用']嗎? –

+0

你的標題說你需要提取圓括號的內容,但是你的文本說你需要將圓括號轉換爲方括號。這是什麼? – TLP

+0

我編輯了這個問題,以更好地反映我的意圖。 –

回答

1

你可以解決它在幾個方面,最簡單的是,直到有沒有做更多的替換隻是執行你的表達。例如:

1 while s/(\((?: [^()?]* | (?0))* \)) \?/[$1]/xg; 

但是,這是非常低效(深度嵌套字符串)。

你能做到這一點的一個通這樣的代替:

s{ 
    (?(DEFINE) 
    (?<r> \((?: [^()]++ | (?&r))*+ \) ) 
) 

    (\() 
    (?= (?: [^()]++ | (?&r))*+ \) \? ) 

    | 

    \) \? 
}{ 
    $2? '[': ']' 
}gex; 
+0

1雖然事情效果很好!如何給正則表達式g開關並沒有做同樣的事情?但是,考慮到' =((((stuff)??I)?like)?',您的正則表達式給了我' =]]]]]]]]]。 –

+0

@NateGlenn,現在開始工作,將$ 1改爲$ 2。 (忘記遞歸組,doh。) – Qtax

+0

是的,現在工作很好。 –

4

您也想看看ysth's solution to that question,並使用工具,已經可以解決這個問題:

use Text::Balanced qw(extract_bracketed); 
$text = '((((stuff)? that)? I)? like)?'; 

for ($i=0; $i<length($text); $i++) { 
    ($match,$remainder) = extract_bracketed(substr($text,$i), '()'); 
    if ($match && $remainder =~ /^\?/) { 
     substr($text,$i) = 
      '[' . substr($match,1,-1) . ']' . substr($remainder,1); 
     $i=-1; # fixed 
    } 
} 
+0

@Ωmega,不錯怎麼樣?即使使用OP的原始示例,該版本也不起作用。 (結果是'[[([stuff] that)?I] like]'。)對於這個簡單的例子,第一個版本可以工作,但是這樣做並不好,因爲它沒有合適的例子,比如'(foo((bar) ?(baz))?)',result'(foo [([bar](baz)?)'。不適用於任何事情,-1直到修正。 – Qtax

+0

fixed。。。。 – mob

2

在舊的Perl版本(前5.10),一個也可以使用代碼斷言和動態正則表達式是:

... 
my $s = '((((stuff)? that)? I)? like)?'; 

# recursive dynamic regex, we need 
# to pre-declare lexical variables 
my $rg; 

# use a dynamically generated regex (??{..}) 
# and a code assertion (?{..}) 
$rg = qr{ 
      (?:      # start expression 
      (?> [^)(]+)    # (a) we don't see any (..) => atomic! 
      |      # OR 
      (      # (b) start capturing group for level 
      \((??{$rg}) \) \?  # oops, we found parentheses \(,\) w/sth 
      )      # in between and the \? at the end 
      (?{ print "[ $^N ]\n" }) # if we got here, print the captured text $^N 
     )*      # done, repeat expression if possible 
     }xs; 

$s =~ /$rg/; 
... 

在比賽中,代碼斷言打印所有的比賽,分別是:

[ (stuff)? ] 
[ ((stuff)? that)? ] 
[ (((stuff)? that)? I)? ] 
[ ((((stuff)? that)? I)? like)? ] 

根據您的要求要使用此,你可以稍微改變代碼斷言,把捕獲括號在正確的地方,並節省在陣列中的匹配:

... 
my @result; 
my $rg; 
$rg = qr{ 
      (?:      
      (?> [^)(]+)    
      |      
      \(((??{$rg})) \) \? (?{ push @result, $^N }) 
     )*      
     }xs; 

$s =~ /$rg/ && print map "[$_]\n", @result; 
... 

它說:

[stuff] 
[(stuff)? that] 
[((stuff)? that)? I] 
[(((stuff)? that)? I)? like] 

問候

rbo