2014-11-07 23 views
8

Tôi muốn chia chuỗi nhiều dòng Python tại dấu phẩy của nó, trừ khi dấu phẩy nằm trong một biểu thức có ngoặc vuông. Ví dụ, chuỗiTách chuỗi tại dấu phẩy trừ khi trong môi trường khung

{J. Doe, R. Starr}, {Lorem 
{i}psum dolor }, Dol. sit., am. et. 

nên được chia thành

['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.'] 

này liên quan đến khớp khung, vì vậy có lẽ regexes không giúp đỡ ở đây. PyParsingcommaSeparatedListgần làm những gì tôi cần ngoại trừ việc trích dẫn (") môi trường được bảo vệ thay vì {} những -delimited.

Bất kỳ gợi ý nào?

+0

AFAIK Python không hỗ trợ đệ quy trong regex. Chỉ để tham khảo, điều này sẽ [thực hiện công việc] (http://regex101.com/r/qD4zV8/1) với PCRE: '(? 'Niềng răng' \ {(?: [^ {}] ++ | \ g ) * \}) (* SKIP) (* FAIL) |, ' –

+0

đây không phải là điều nhỏ nhặt bạn yêu cầu ... ... regexes không hữu ích vì bạn yêu cầu máy trạng thái có bộ nhớ để khớp với các mục kèm theo. (brakcets, dấu ngoặc kép, vv) –

+0

Nó không thể được thực hiện mà không có regex đệ quy (những người làm đệ quy). Tôi nghĩ rằng Python có một phiên bản mới hơn thực hiện điều này ngay bây giờ. Hài hước như thế nào Perl đến từ Python, Perl lá nó trong bụi. – sln

Trả lời

10

Viết riêng tùy chỉnh tách chức năng của bạn:

input_string = """{J. Doe, R. Starr}, {Lorem 
{i}psum dolor }, Dol. sit., am. et.""" 


expected = ['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.'] 

def split(s): 
    parts = [] 
    bracket_level = 0 
    current = [] 
    # trick to remove special-case of trailing chars 
    for c in (s + ","): 
     if c == "," and bracket_level == 0: 
      parts.append("".join(current)) 
      current = [] 
     else: 
      if c == "{": 
       bracket_level += 1 
      elif c == "}": 
       bracket_level -= 1 
      current.append(c) 
    return parts 

assert split(input_string), expected 
+0

làm việc tốt đẹp ... :) đây là câu trả lời đúng hiện tại afaik –

+0

Tốt, nhưng giả định với việc thực hiện này là không có ký tự "{" hoặc "}" trong chuỗi có thể không thuộc nhóm. tức là ": -}" Nếu khả năng đó có thể tồn tại, cần phải có một số xem xét để giải quyết vấn đề. –

5

Bạn có thể sử dụng re.split trong trường hợp này:

>>> from re import split 
>>> data = '''\ 
... {J. Doe, R. Starr}, {Lorem 
... {i}psum dolor }, Dol. sit., am. et.''' 
>>> split(',\s*(?![^{}]*\})', data) 
['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.'] 
>>> 

Dưới đây là một lời giải thích về những gì mô hình Regex phù hợp:

,  # Matches , 
\s*  # Matches zero or more whitespace characters 
(?!  # Starts a negative look-ahead assertion 
[^{}]* # Matches zero or more characters that are not { or } 
\}  # Matches } 
)  # Closes the look-ahead assertion 
+1

Sẽ không thất bại này cho các ví dụ phức tạp hơn một chút của các dấu ngoặc lồng nhau? Ví dụ. '" {J. Doe, R. Starr {x, {y}}}, {Lorem {i} psum dolor}, Dol. Ngồi, và. " –

+0

@ajcr - Có, nó sẽ thất bại. Nhưng đó là lý do tại sao tôi nói "trong trường hợp này". Các mô hình tôi đã không phải là chống đạn và chỉ có thể xử lý các chuỗi đơn giản. Cụ thể, nó có nghĩa là cho các chuỗi không có dấu ngoặc nhọn lồng nhau bằng dấu phẩy, như trong ví dụ của OP. Tuy nhiên, nếu OP đang làm việc với các chuỗi phức tạp như vậy, thì tốt hơn là nên bỏ qua Regex và xây dựng một trình phân tích cú pháp thay thế. – iCodez

+0

Tôi không nghĩ bạn có thể khái quát hóa điều này để trở thành giải pháp ở mọi cấp độ. – sln

2

Lucas Trzesniewski's comment thực sự có thể được sử dụng trong Python với PyPi regex module (tôi chỉ thay tên nhóm với một số để làm cho nó ngắn hơn):

>>> import regex 
>>> r = regex.compile(r'({(?:[^{}]++|\g<1>)*})(*SKIP)(*FAIL)|\s*,\s*') 
>>> s = """{J. Doe, R. Starr}, {Lorem 
{i}psum dolor }, Dol. sit., am. et.""" 
>>> print(r.split(s)) 
['{J. Doe, R. Starr}', None, '{Lorem\n{i}psum dolor }', None, 'Dol. sit.', None, 'am. et.'] 

Các mô hình - ({(?:[^{}]++|\g<1>)*})(*SKIP)(*FAIL) - phù hợp với {...{...{}...}...} như cấu trúc (như { trận {, (?:[^{}]++|\g<1>)* trận 0+ lần xuất hiện của 2 lựa chọn: 1) bất kỳ 1+ ký tự nào khác ngoài {} (số [^{}]++), 2) văn bản khớp với toàn bộ mô hình ({(?:[^{}]++|\g<1>)*})). Động từ (*SKIP)(*FAIL) làm cho động cơ bỏ qua toàn bộ giá trị khớp từ bộ đệm khớp, do đó, di chuyển chỉ mục đến cuối khớp và không giữ gì để trả về (chúng tôi "bỏ qua" những gì chúng tôi đã so khớp).

\s*,\s* khớp với dấu phẩy được đính kèm với hơn 0 khoảng trắng.

Giá trị None xuất hiện vì có nhóm chụp trong chi nhánh đầu tiên trống khi chi nhánh thứ hai khớp. Chúng ta cần sử dụng một nhóm chụp trong nhánh thay thế đầu tiên để đệ quy. Để xóa các phần tử trống, hãy sử dụng hiểu:

>>> print([x for x in r.split(s) if x]) 
['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.'] 
Các vấn đề liên quan