2010-01-06 41 views
7

Tôi cần phải tách một chuỗi thành một danh sách các phần trong Ruby, nhưng tôi cần phải bỏ qua các thứ bên trong paramentheses. Ví dụ:Tách chuỗi trong Ruby, bỏ qua nội dung của dấu ngoặc đơn?

A +4, B +6, C (hello, goodbye) +5, D +3 

Tôi muốn trong danh sách kết quả là:

[0]A +4 
[1]B +6 
[2]C (hello, goodbye) +5 
[3]D +3 

Nhưng tôi không thể chỉ đơn giản là chia rẽ về dấu phẩy, bởi vì đó sẽ chia các nội dung của dấu ngoặc đơn. Có cách nào để phân chia các công cụ mà không cần phân tích cú pháp các dấu phẩy trong dấu ngoặc ôm vào cái gì khác không?

Cảm ơn.

+0

Cẩn thận với khuôn mặt cau mày :-(rối tung lên các phân tích cú pháp –

Trả lời

13

Hãy thử điều này:

s = 'A +4, B +6, C (hello, goodbye) +5, D +3' 
tokens = s.scan(/(?:\(.*?\)|[^,])+/) 
tokens.each {|t| puts t.strip} 

Output:

A +4 
B +6 
C (hello, goodbye) +5 
D +3 

Một giải thích ngắn gọn:

(?:  # open non-capturing group 1 
    \(  # match '(' 
    .*?  # reluctatly match zero or more character other than line breaks 
    \)  # match ')' 
    |  # OR 
    [^,]  # match something other than a comma 
)+   # close non-capturing group 1 and repeat it one or more times 

Một lựa chọn khác là để chia trên một dấu phẩy sau đó một số không gian chỉ khi là người đầu tiên dấu ngoặc đơn có thể được nhìn thấy khi nhìn về phía trước là dấu ngoặc đơn mở (hoặc không có dấu ngoặc đơn nào cả). phần cuối của chuỗi):

s = 'A +4, B +6, C (hello, goodbye) +5, D +3' 
tokens = s.split(/,\s*(?=[^()]*(?:\(|$))/) 
tokens.each {|t| puts t} 

sẽ tạo ra cùng một đầu ra, nhưng tôi tìm thấy phương pháp dọn dẹp scan.

+0

# => [ "Một 4", "B 6", "C (! Xin chào, tạm biệt) +5 "," D +3 "] Có vẻ hoàn hảo với tôi. Có thể muốn #trim nó để loại bỏ khoảng trắng xung quanh –

+0

:) đã thấy các khoảng trống và thêm' trim' –

+0

Câu trả lời hay, cảm ơn:) – Colen

5
string = "A +4, B +6, C (hello, goodbye) +5, D +3" 
string.split(/ *, *(?=[^\)]*?(?:\(|$))/) 
# => ["A +4", "B +6", "C (hello, goodbye) +5", "D +3"] 

Làm thế nào regex này hoạt động:

/ 
    *, *  # find comma, ignoring leading and trailing spaces. 
    (?=   # (Pattern in here is matched against but is not returned as part of the match.) 
    [^\)]*? # optionally, find a sequence of zero or more characters that are not ')' 
    (?:  # <non-capturing parentheses group> 
     \(  #  left paren ')' 
     |  #  - OR - 
     $  #  (end of string) 
    ) 
) 
/
+0

Điều đó có thể hơi khó hiểu mà không có lời giải thích cho những người đam mê regex tâm huyết mờ nhạt có lẽ là OP! :). Nhưng một giải pháp tốt tuy nhiên. –

+0

Tính năng này hoạt động như thế nào? Tôi không thể tìm thấy bất kỳ tài liệu hướng dẫn tốt về cách regex làm việc với chia - như Bart K. nói rằng tôi không phải là tuyệt vời với regexes – Colen

+0

@Colen, tôi đăng một regex rất giống như một giải pháp thứ hai bao gồm cả một lời giải thích. –

Các vấn đề liên quan