2012-10-11 27 views
14

Đây là của Ruby 1.8.7 nhưng phải tương tự như đối 1.9.xcủa Ruby Chuỗi chia với regex

Tôi cố gắng để tách một chuỗi ví dụ:

a = "foo.bar.size.split('.').last" 
# trying to split into ["foo", "bar","split('.')","last"] 

Về cơ bản tách nó trong lệnh nó đại diện, tôi đang cố gắng để làm điều đó với biểu thức chính quy nhưng không chắc chắn như thế nào, ý tưởng là sử dụng regexp

a.split(/[a-z\(\)](\.)[a-z\(\)]/) 

đây cố gắng sử dụng nhóm (\.) để chia nó với nhưng điều này có vẻ không phải là cách tiếp cận tốt.

+1

Nó không phải là dễ dàng như bạn nghĩ. – sawa

+1

@sawa: bạn đã đóng một câu hỏi bởi vì bạn nghĩ rằng nó quá khó? – iconoclast

+0

@iconoclast Tôi không nhớ, nhưng không phải vì lý do bạn nghĩ. – sawa

Trả lời

23

Tôi nghĩ rằng điều này sẽ làm điều đó:

a.split(/\.(?=[\w])/) 

Tôi không biết có bao nhiêu bạn biết về regex, nhưng (?=[\w]) là một lookahead nói rằng "chỉ phù hợp với dấu chấm nếu ký tự tiếp theo là một bức thư loại nhân vật ". Một lookahead sẽ không thực sự lấy các văn bản nó phù hợp. Nó chỉ "trông". Vì vậy, kết quả chính xác là những gì bạn đang tìm kiếm:

> a.split(/\.(?=[\w])/) 
=> ["foo", "bar", "size", "split('.')", "last"] 
+0

Wow, tuyệt vời và cảm ơn bạn đã biết thông tin về lookahead. Không, tôi không biết điều đó và đó là điều tuyệt vời để học dường như rất hữu ích. –

+1

Bạn được chào đón. Trang web này thật tuyệt vời: http://www.regular-expressions.info/ –

+1

Điều này sẽ tách một chuỗi như '" foo.bar.size.split ('. Bar'). "Last thành' ["foo", "bar", "size", "split ('", "bar')", "last"] '. – sawa

2

đây tôi không có ruby ​​env. Tôi đã thử với python re.split().

In : re.split("(?<!')\.(?!')",a) 
Out: ['foo', 'bar', 'size', "split('.')", 'last'] 

regex trên có lookahead tiêu cực lookbehind, để đảm bảo chỉ có "chấm" giữa dấu nháy đơn sẽ không làm việc như tách.

tất nhiên, đối với ví dụ cụ thể của bạn, một trong những điều tra hoặc nhìn là đủ. bạn có thể chọn đúng cách cho yêu cầu của bạn.

+0

Như bạn có thể nhận thấy, điều này sẽ không hoạt động chính xác cho '[" foo "," bar "," size "," split ('o.b') "," last "]'. – sawa

7

Tôi e rằng các cụm từ thông dụng sẽ không đưa bạn đi rất xa. Xem xét ví dụ các biểu thức sau (cũng là Ruby hợp lệ)

"(foo.bar.size.split('.')).last" 
"(foo.bar.size.split '.').last" 
"(foo.bar.size.split '(.) . .(). .').last" 

Vấn đề là danh sách các cuộc gọi thực sự là một cây gọi. Giải pháp đơn giản nhất trong tầm nhìn có lẽ là sử dụng một phân tích cú pháp Ruby và chuyển đổi cây phân tích cú pháp theo yêu cầu của bạn (trong ví dụ này, chúng tôi đang đệ quy giảm dần vào cây gọi, thu thập các cuộc gọi vào một danh sách):

# gem install ruby_parser 
# gem install awesome_print 
require 'ruby_parser' 
require 'ap' 

def calls_as_list code 
    tree = RubyParser.new.parse(code) 

    t = tree 
    calls = [] 

    while t 
     # gather arguments if present 
     args = nil 
     if t[3][0] == :arglist 
      args = t[3][1..-1].to_a 
     end 
     # append all information to our list 
     calls << [t[2].to_s, args] 
     # descend to next call 
     t = t[1] 
    end 

    calls.reverse 
end 

p calls_as_list "foo.bar.size.split('.').last" 
#=> [["foo", []], ["bar", []], ["size", []], ["split", [[:str, "."]]], ["last", []]] 
p calls_as_list "puts 3, 4" 
#=> [["puts", [[:lit, 3], [:lit, 4]]]] 

Và để hiển thị cây phân tích cú pháp của bất kỳ đầu vào:

ap RubyParser.new.parse("puts 3, 4")