2011-12-12 45 views
5

Tôi có chuỗi sau:Perl chia và biểu thức chính quy

'100% California Grown Olives, Water, Salt And Ferrous Gluconate (An,Iron, Derivative),asasd, sadasda' 

Tôi đang cố gắng để tách nó bằng cách /,/ nhưng chỉ khi nó không dấu ngoặc bên trong, ví dụ, trong trường hợp này kết quả nên :

100% California Grown Olives 
Water 
Salt And Ferrous Gluconate (An,Iron, Derivative) 
asasd 
sadasda 

cảm ơn,

+1

Có khả năng có dấu ngoặc ôm không? Nếu vậy, regexes có thể không phù hợp với hóa đơn. –

+1

không, không thể. chỉ có một cặp dấu ngoặc đơn, hoặc cặp vợ chồng nhưng KHÔNG lồng nhau – snoofkin

Trả lời

11
@result = split(m/,(?![^()]*\))/, $subject); 

T phân chia của mình trên dấu phẩy chỉ khi dấu ngoặc đơn tiếp theo sau (nếu có) không phải là dấu ngoặc đơn đóng. Như Jack Maney đã lưu ý một cách chính xác, điều này có thể dẫn đến thất bại nếu các dấu ngoặc đơn lồng nhau có thể xảy ra.

Giải thích:

,  # Match a comma. 
(?!  # Assert that it's impossible to match... 
[^()]* # any number of non-parenthesis characters 
\)  # followed by a closing parenthesis 
)  # End of lookahead assertion 
1

Trước tiên, bạn cần phải quyết định những gì tạo nên dấu ngoặc, và nếu họ có thể được lồng vào nhau. (cho câu trả lời này, tôi sẽ giả định rằng họ có thể). Sau đó, bạn cần phải loại bỏ những khối Dấu ngoặc đơn từ văn bản và thay thế nó bằng một trình giữ chỗ:

my @parens; 
$str =~ s/(\((?: (?0)|[^()])* \))/push @parens, $1; "PARENS_$#parens"/gex; 

Vì vậy, bây giờ bạn chỉ còn lại cái gì đó trông giống như:

'100% California Grown Olives, Water, Salt And Ferrous Gluconate PAREN_0,asasd, 
sadasdas.' 

Và nó là đơn giản bây giờ để chia nó trên dấu phẩy. Sau đó, trên mỗi phần tách, quét cho PAREN_\d+ mã thông báo và thay thế chúng bằng các mã từ mảng @parens. Bạn có thể cần phải sử dụng một tên trình giữ chỗ độc đáo hơn tùy thuộc vào nội dung nguồn của bạn.

Cái gì như:

s/PARENS_(\d+)/$parens[$1]/ge for my @segs = split /,\s*/ => $str; 

say for @segs; 

mà cho một ví dụ chuỗi:

my $str = "foo (b,a,r), baz (foo, (bar), baz), biz"; 

in:

foo (b,a,r) 
baz (foo, (bar), baz) 
biz 
+0

Tôi không nghĩ rằng bạn cần phải đánh giá '$ parens [$ 1]'. – TLP

0

Bạn có thể tìm thấy nó dễ dàng hơn để xây dựng một regexp cho những gì bạn muốn phù hợp, thay vì những gì bạn muốn xóa. (Điều này giả định rằng bạn không muốn giới hạn số lượng kết quả trùng khớp.)

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