2012-03-15 18 views
0

給定一個正則表達式:如何獲取正則表達式中的(可能嵌套的)捕獲組?

/say (hullo|goodbye) to my lovely (.*)/ 

和一個字符串:

"my $2 is happy that you said $1" 

什麼是獲得一個包含正則表達式的捕獲組串正則表達式的最好方法?那就是:

/my (.*) is happy that you said (hullo|goodbye)/ 

顯然,我可以在原來的正則表達式的字符串表示使用正則表達式,但這將嵌套捕捉組可能存在困難。

我在使用Ruby。

class Regexp 
    def capture_groups 
    self.to_s[1..-2].scan(/\(.*?\)/) 
    end 
end 

regexp.capture_groups.each_with_index do |capture, idx| 
    string.gsub!("$#{idx+1}", capture) 
end 
/^#{string}$/ 
+0

最終目標是什麼? – 2012-03-15 22:45:19

+0

感謝您的期待 - 我已經提出了更清晰的問題(我希望)。 – 2012-03-15 23:05:05

+0

我不明白爲什麼這是被拒絕或投票結束。對於OP,您可能只想調查現有的正則表達式引擎,或者查看是否有一種方法可以與現有的正則表達式匹配(IIRC主要是C)。 – 2012-03-16 16:29:22

回答

1

所以一旦我意識到我真正需要的是一個正則表達式解析器,事情就開始落實了。我發現這個項目:

能夠生成匹配正則表達式的字符串。它使用http://treetop.rubyforge.org/定義正則表達式語法。不幸的是,它定義的語法不完整,雖然對很多情況有用。

我也偶然發現了https://github.com/mjijackson/citrus,它和Treetop有類似的工作。

然後我發現了這個令人興奮的寶石:

它定義了一個完整的正則表達式的語法和解析正則表達式爲可操作樹。然後,我能夠走過樹並挑選出我想要的樹的部分(捕獲組)。

不幸的是,有一個小錯誤,在我的叉子裏修復:https://github.com/LaunchThing/regexp_parser

這裏是我的補丁,正則表達式,使用固定寶石:

class Regexp 
    def parse 
    Regexp::Parser.parse(self.to_s, 'ruby/1.9') 
    end 

    def walk(e = self.parse, depth = 0, &block) 
    block.call(e, depth) 
    unless e.expressions.empty? 
     e.each do |s| 
     walk(s, depth+1, &block) 
     end 
    end 
    end 

    def capture_groups 
    capture_groups = [] 
    walk do |e, depth| 
     capture_groups << e.to_s if Regexp::Expression::Group::Capture === e 
    end 
    capture_groups 
    end 
end 

然後我就可以用這個在我的應用程序,以使我的字符串替換 - 最終目標 - 沿着這些線路:

from = /^\/search\/(.*)$/ 
to = '/buy/$1' 

to_as_regexp = to.dup 

# I should probably make this gsub tighter 
from.capture_groups.each_with_index do |capture, idx| 
    to_as_regexp.gsub!("$#{idx+1}", capture) 
end 
to_as_regexp = /^#{to_as_regexp}$/ 

# to_as_regexp = /^\/buy\/(.*)$/ 

我希望這可以幫助別人。

2

我猜你需要創建自己的功能,將做到這一點:我的簡單實現沿的線,所以竟把

  • 創建空字典groupsactive_groups和初始化counter = 1
  • 迭代字符串表示中的字符:
    • 如果當前字符= '('和先前字符集!= \
      • 添加counter關鍵active_groups和增加,如果當前字符= ')'和以前charaster counter
    • 當前字符添加到所有active_groups
    • != \
      • active_groups刪除最後一個項目(鍵,值)並將其添加到groups
  • 如果需要

轉換groups到陣列您可能還想實施:

  • 未轉義'['']'之間ignore = True
  • 復位counter如果當前字符= '|'active_groups是空(或減小counter如果active_group不爲空)從評論

    UPDATES

  • ingore非捕獲組開始
+1

是的,需要構建足夠的解析器來識別捕獲組。注意'(?:。*)'不是一個捕獲。 – dbenhur 2012-03-16 03:20:34