2010-04-15 43 views
6

Vậy tại sao điều này không hoạt động? Tôi đang tạo một regex mà sẽ phù hợp với một công thức (đó là một phần của một mô tả tiêu chuẩn lớn hơn). Nhưng tôi bị kẹt ở đây, vì nó không xuất hiện để phù hợp với các công thức nhúng trong một công thức.ruby ​​đệ quy regex

stat  = /(Stat3|Stat2|Stat1)/ 

number_sym = /[0-9]*/ 
formula_sym = /((target's)?#{stat}|#{number_sym}|N#{number_sym})\%?/ 
math_sym = /(\+|\-|\*|\/|\%)/ 

formula  = /^\((#{formula}|#{formula_sym})(#{math_sym} (#{formula}|#{formula_sym}))?\)$/ 

p "(target's Stat2 * N1%)".match(formula).to_s #matches 
p "((target's Stat2 * N1%) + 3)".match(formula).to_s #no match 
p "(Stat1 + ((target's Stat2 * N1%) + 3))".match(formula).to_s #no match 

Trả lời

7

Khi bạn sử dụng cú pháp #{ }, Ruby chuyển đổi đối tượng biểu thức chính quy thành một chuỗi sử dụng to_s. Hãy xem những gì sẽ xảy ra khi bạn chuyển đổi một đối tượng biểu thức chính quy để một chuỗi:

irb> re = /blah/ 
    => /blah/ 
irb> re.to_s 
    => "(?-mix:blah)" 
irb> "my regex: #{re}" 
    => "my regex: (?-mix:blah)" 
irb> /my regex: #{re}/ 
    => /my regex: (?-mix:blah)/ 

Để có được chuỗi bạn muốn (trong ví dụ của tôi, "blah"), sử dụng Regexp#source phương pháp:

irb> re.source 
"blah" 

Vì vậy, để sử dụng ví dụ của bạn:

formula_sym = /((target's)?#{stat.source}|#{number_sym.source}|N#{number_sym.source})\%?/ 
+0

cảm ơn ... và tôi đã khám phá lý do tại sao nó không hoạt động ... tôi đoán tôi nên đặt câu hỏi của mình là "làm thế nào tôi có thể làm việc" .... trông giống như # {formula.source} đã chỉ ra rằng công thức vẫn là nil. –

1

bạn không thể sử dụng đệ quy như thế: các #{formula} s trong định nghĩa của bạn về formula được chuyển đổi thành chuỗi rỗng. Những gì bạn muốn vượt quá khả năng của biểu thức chính quy - biểu thức thông thường thậm chí không thể khớp với dấu ngoặc đơn lồng nhau. Tôi nghi ngờ bạn sẽ cần một trình phân tích cú pháp thực tế để làm những gì bạn muốn. Hãy xem ví dụ treetop.

+0

tuyệt vời ... treetop sẽ cho phép tôi di chuyển thông số định nghĩa hiện tại của mình vào nó một cách dễ dàng. Cảm ơn! –

3
/(
    (?<non_grouping_char> 
    [^\(\{\[\<\)\}\]\>] 
){0} 
    (?<parens_group> 
    \(\g<content> \) 
){0} 
    (?<brackets_group> 
    \[ \g<content> \] 
){0} 
    (?<chevrons_group> 
    \< \g<content> \> 
){0} 
    (?<braces_group> 
    \{ \g<content> \} 
){0} 
    (?<balanced_group> 
    (?> 
     \g<parens_group> | 
     \g<brackets_group> | 
     \g<chevrons_group> | 
     \g<braces_group> 
    ) 
){0} 
    (?<content> 
    (?> \g<balanced_group> | \g<non_grouping_char>)* 
){0} 
    \A \g<content> \Z 
)/uix 

Bia cho tôi nếu điều này giúp bạn. Làm việc cho tôi. Hoạt động trong bất kỳ công cụ regexp nào cho phép các nhóm được đặt tên. Nó sẽ xác thực bất kỳ nội dung nào không có nhóm hoặc các nhóm ký tự lồng nhau, đến bất kỳ độ sâu nào.

+1

Nếu chúng ta gặp nhau, chắc chắn tôi sẽ trả cho bạn một ly bia. Hương vị yêu thích của bạn là gì? :) Kể từ đó, tôi bỏ phiếu! – Stephan