2012-12-31 35 views
9

Điều này giống như một câu hỏi thực sự đơn giản, nhưng tôi không thể tìm thấy câu trả lời ở bất kỳ đâu.Không thể tìm thấy cú pháp chính xác của regex để khớp với dòng mới hoặc kết thúc của chuỗi

(Ghi chú:. Tôi đang sử dụng Python, nhưng điều này không phải vấn đề)

Nói rằng tôi có chuỗi sau:

s = "foo\nbar\nfood\nfoo" 

Tôi chỉ đơn giản là cố gắng tìm một regex mà sẽ phù hợp cả hai trường hợp "foo", nhưng không phải "thực phẩm", dựa trên thực tế là "foo" trong "thực phẩm" không được theo sau bởi một dòng mới hoặc kết thúc của chuỗi.

Đây có lẽ là một cách quá phức tạp để thể hiện câu hỏi của tôi, nhưng nó mang lại một cái gì đó cụ thể để làm việc.

Dưới đây là một số trong những điều tôi đã cố gắng, với kết quả (Lưu ý: kết quả tôi muốn là [foo\n, foo]):

foo[\n\Z] => ['foo\n']

foo(\n\Z) => ['\n' , ''] < = Điều này có vẻ phù hợp với newline và EOS, nhưng không phải là foo

foo($|\n) => ['\n', '']

(foo)($|\n) => [(foo, '\n'), (foo, '')] < = Hầu như ở đó, và đây là một kế hoạch sử dụng được B, nhưng tôi muốn tìm ra giải pháp hoàn hảo.

Điều duy nhất tôi phát hiện ra rằng không làm việc là:

foo$|foo\n => ['foo\n', ` 'foo']

Điều này là tốt cho một ví dụ đơn giản như vậy, nhưng nó rất dễ dàng để xem nó như thế nào có thể trở nên khó sử dụng với một biểu thức lớn hơn nhiều (và có, điều này foo là một đứng trong biểu thức lớn hơn tôi đang thực sự sử dụng).


Thú vị sang một bên: Các câu hỏi SO gần nhất tôi có thể tìm cho vấn đề của tôi là này một: In regex, match either the end of the string or a specific character

Ở đây, tôi chỉ đơn giản là có thể thay thế \n cho 'nhân vật cụ thể' của tôi. Bây giờ, câu trả lời được chấp nhận sử dụng regex /(&|\?)list=.*?(&|$)/. Tôi nhận thấy rằng OP đã sử dụng JavaScript (câu hỏi đã được gắn thẻ với thẻ javascript), vì vậy có thể trình thông dịch regex JavaScript khác, nhưng khi tôi sử dụng các chuỗi chính xác được đưa ra trong câu hỏi với regex ở trên, tôi nhận được kết quả xấu:

>>> findall("(&|\?)list=.*?(&|$)", "index.php?test=1&list=UL") 
[('&', '')] 
>>> findall("(&|\?)list=.*?(&|$)", "index.php?list=UL&more=1") 
[('?', '&')] 

Vì vậy, tôi bị bối rối.

+0

Bạn có biết về [re.MULTILINE] (http://docs.python.org/2/library/re.html) không? –

+0

Có, và tôi biết rằng nó sẽ làm việc cho tôi bằng Python, nhưng tôi muốn tìm một giải pháp độc lập về ngôn ngữ. –

Trả lời

7
>>> import re 
>>> re.findall(r'foo(?:$|\n)', "foo\nbar\nfood\nfoo") 
['foo\n', 'foo'] 

(?:...) làm cho một non-capturing group.

này hoạt động vì (từ re module reference):

re.findall (pattern, chuỗi, cờ = 0)

Return tất cả không chồng chéo các trận đấu của mô hình trong chuỗi, như một danh sách các chuỗi . Chuỗi được quét từ trái sang phải và các kết quả khớp được trả về theo thứ tự tìm thấy. Nếu một hoặc nhiều nhóm có mặt trong mẫu, hãy trả về danh sách các nhóm; đây sẽ là danh sách các bộ dữ liệu nếu mẫu có nhiều nhóm. Các trận đấu trống được bao gồm trong kết quả trừ khi họ chạm vào đầu của một trận đấu khác.

+0

Huh. Tại sao nó sử dụng một nhóm không chụp thay vì một nhóm tiêu chuẩn hoạt động? tại sao không cũ 'r'foo ($ | \ n)' 'làm điều tương tự? –

+0

Ngoài ra, đây là cái tôi muốn. Cảm ơn rất nhiều! –

+1

Nếu bạn có '$ | \ n' trong một nhóm bình thường, bạn sẽ khớp (và chỉ khớp) các ngắt dòng (vì không có gì khác trong nhóm chụp). Bạn có thể đặt foo trong một nhóm là tốt, nhưng sau đó bạn sẽ lại kết thúc với kết quả nhóm thêm cho các ngắt dòng. – poke

1

Nếu bạn chỉ quan tâm đến việc foo:

In [42]: import re 

In [43]: strs="foo\nbar\nfood\nfoo" 

In [44]: re.findall(r'\bfoo\b',strs) 
Out[44]: ['foo', 'foo'] 

\b là biểu thị một ranh giới từ:

\b

Phù hợp với chuỗi rỗng, nhưng chỉ ở đầu hoặc cuối của một từ. Một từ được định nghĩa là một chuỗi gồm các ký tự chữ và số hoặc gạch dưới , do đó, kết thúc của một từ được biểu thị bằng khoảng trắng hoặc ký tự không phải chữ và số, không gạch dưới. Lưu ý rằng chính thức, \ b là được định nghĩa là ranh giới giữa ký tự \ w và a \ W (hoặc vice versa) hoặc giữa \ w và đầu/cuối của chuỗi, do đó, các ký tự chính xác được coi là chữ và số phụ thuộc vào các giá trị của cờ UNICODE và LOCALE. Ví dụ: r '\ bfoo \ b' khớp với 'foo', 'foo.', '(Foo)', 'bar foo baz' nhưng không phải 'foobar' hoặc 'foo3'. Bên trong một phạm vi ký tự, \ b đại diện cho ký tự backspace , để tương thích với các chuỗi ký tự của Python.

(Source)

+0

Có thể đáng giải thích ['\ b'] (http://docs.python.org/2/library/re.html#regular-expression-syntax). (Đã chỉnh sửa) –

+0

Một lần nữa, 'foo' chỉ là một trình giữ chỗ cho một biểu thức phức tạp hơn nhiều. Những gì tôi thực sự tìm kiếm là làm thế nào để kiểm tra chống lại sự kết thúc của dòng hoặc kết thúc của chuỗi. Trong nhiều trường hợp, việc sử dụng '\ b' để kiểm tra các ranh giới từ có thể phá vỡ biểu thức. Mặc dù vậy, suy nghĩ tốt. –

+2

@KenB Vui lòng cung cấp các ví dụ thực sự hiển thị những gì bạn muốn - thật khó để đoán yêu cầu của bạn nếu bạn không hiển thị chúng. –

2

Bạn có thể sử dụng re.MULTILINE và bao gồm một tùy chọn linebreak sau các $ trong mô hình của bạn:

s = "foo\nbar\nfood\nfoo" 
pattern = re.compile('foo$\n?', re.MULTILINE) 
print re.findall(pattern, s) 
# -> ['foo\n', 'foo'] 
+0

Tôi thích nó, nhưng tôi thực sự thích tìm một giải pháp bất khả tri về ngôn ngữ. Vì 're.MULTILINE' là Python cụ thể, tôi nên tránh nó, để sử dụng trong các ngôn ngữ khác trong tương lai. –

+3

Công cụ biểu thức chính quy nhất hỗ trợ tùy chọn nhiều dòng. Bạn cũng có thể nhúng nó trực tiếp vào mẫu: 're.findall ('(? M) foo $ \ n?', S)'. – omz

+1

@KenB Chính xác, các cờ như MULTILINE không phải là Python cụ thể, chúng chỉ có cú pháp khác nhau trên các ngôn ngữ khác (ví dụ: trong Perl 're.MULTILINE' sẽ là' $ s = ~/blah/m' hoặc một cái gì đó). Tôi không bao giờ nhận ra những lá cờ có thể được bao gồm trong các mẫu, đó là thực sự hữu ích để biết, cảm ơn! : D – dbr

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