2009-08-06 15 views
443

Tôi biết rằng tôi có thể phủ nhận nhóm ký tự như trong [^bar] nhưng tôi cần cụm từ thông dụng khi từ chối áp dụng cho từ cụ thể - trong ví dụ của tôi làm cách nào để phủ nhận "bar" thực tế chứ không phải "any chars in bar"?Làm thế nào để phủ nhận từ cụ thể trong regex?

+1

Có thể trùng lặp của [Biểu thức chính quy cho phù hợp với dòng không chứa từ?] (Http: // stackoverflow.com/questions/406230/regular-expression-to-match-line-that-không-chứa-a-word) –

Trả lời

480

Một cách tuyệt vời để làm điều này là sử dụng negative lookahead:

^(?!.*bar).*$ 
+7

Điều này nói lên tất cả (tôi có lẽ đã bắt đầu với (?! Bar) và được dựng lên). Tôi không hiểu tại sao những người khác lại khiến nó phức tạp đến vậy. – Beta

+24

Thật không may, điều này không hoạt động với tất cả các ngôn ngữ. – JAB

+4

nhân vật bắt đầu dòng lúc đầu thực hiện một công việc khá tốt. – dhblah

31

Bạn có thể hoặc là sử dụng một negative look-ahead or look-behind:

^(?!.*?bar).* 
^(.(?<!bar))*?$ 

Hoặc sử dụng chỉ cơ bản:

^(?:[^b]+|b(?:$|[^a]|a(?:$|[^r])))*$ 

Những tất cả trận đấu bất cứ điều gì mà không chứa bar.

+0

Ngôn ngữ nào không hỗ trợ (tiêu cực) nhìn phía sau và/hoặc (tiêu cực) nhìn-aheads trong regex ? – JAB

+4

Tôi nghĩ rằng vấn đề đang được thực hiện là, nhìn vào mô hình của bạn, không rõ ràng là tất cả những gì bạn đang làm là từ chối từ "bar". –

+0

@Bryan: Và, trên thực tế, nó không từ chối từ "bar". Nó chỉ từ chối "b" khi tiếp theo là "ar". – JAB

57

Trừ khi hiệu suất là mối quan tâm tối đa, thường dễ dàng hơn khi chạy kết quả của bạn thông qua thẻ thứ hai, bỏ qua những kết quả phù hợp với những từ bạn muốn phủ nhận.

Cụm từ thông dụng thường có nghĩa là bạn đang thực hiện kịch bản hoặc một số tác vụ có hiệu suất thấp, vì vậy hãy tìm giải pháp dễ đọc, dễ hiểu và dễ bảo trì.

40

Regex sau sẽ thực hiện những gì bạn muốn (miễn là giao diện tiêu cực và lookaheads được hỗ trợ), kết hợp mọi thứ đúng cách; vấn đề duy nhất là nó khớp với các ký tự riêng lẻ (nghĩa là mỗi đối sánh là một ký tự đơn chứ không phải tất cả các ký tự giữa hai "thanh" liên tiếp), có thể dẫn đến khả năng cao trên đầu nếu bạn đang làm việc với các chuỗi rất dài.

b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar] 
+6

Thay vì những bản cập nhật nhiều mà buộc chúng tôi đọc các câu trả lời sai trước khi đến câu trả lời cuối cùng của bạn, tại sao không viết lại câu trả lời của bạn để hoàn thành, nhưng không có phần xấu khó hiểu? Nếu ai đó thực sự quan tâm đến lịch sử chỉnh sửa, họ có thể sử dụng các tính năng được tích hợp sẵn của trang web này. –

+12

Đã hai năm rưỡi kể từ khi tôi viết câu trả lời này, nhưng chắc chắn. – JAB

+2

damn mà đau, hãy thử này (? :(?! bar).) * – Bob

1

Chỉ cần nghĩ đến cái gì khác mà có thể được thực hiện. Nó rất khác với câu trả lời đầu tiên của tôi, vì nó không sử dụng các biểu thức chính quy, vì vậy tôi quyết định làm một bài trả lời thứ hai.

Sử dụng ngôn ngữ của phương thức lựa chọn split() phương thức tương đương trên chuỗi có từ phủ định làm đối số cho nội dung cần chia nhỏ. Ví dụ sử dụng Python:

>>> text = 'barbarasdbarbar 1234egb ar bar32 sdfbaraadf' 
>>> text.split('bar') 
['', '', 'asd', '', ' 1234egb ar ', '32 sdf', 'aadf'] 

Điều tốt đẹp về cách làm theo cách này, trong Python ít nhất (tôi không nhớ liệu chức năng này có giống nhau hay không, ví dụ, Visual Basic hoặc Java), là nó cho phép bạn biết gián tiếp khi "bar" được lặp lại trong chuỗi do thực tế rằng các chuỗi rỗng giữa "bar" được bao gồm trong danh sách kết quả (mặc dù chuỗi trống ở đầu là do có một "thanh" "ở đầu chuỗi). Nếu bạn không muốn điều đó, bạn có thể chỉ cần xóa các chuỗi rỗng khỏi danh sách.

+0

Câu hỏi đặc biệt yêu cầu về regex ... –

+2

@Ajk_P có nhưng loại câu trả lời có thể giúp OP nghĩ bên ngoài hộp, họ có thể đã được sửa chữa trên regexes không nhận ra rằng nó có thể được giải quyết mà không có chúng. – Petruza

21

Tôi đã xem qua chủ đề diễn đàn này trong khi cố gắng để xác định một regex cho các tuyên bố sau tiếng Anh:

Với một chuỗi đầu vào, trận đấu mọi thứtrừ chuỗi đầu vào này là chính xác 'bar'; ví dụ tôi muốn kết hợp 'rào cản' và 'phá rối' cũng như 'foo'.

Đây là regex tôi đến với

^(bar.+|(?!bar).*)$ 
dịch

My tiếng Anh của regex là "phù hợp với chuỗi nếu nó bắt đầu với 'bar' và nó có ít nhất một nhân vật khác, hoặc nếu chuỗi không bắt đầu bằng 'bar'

+0

@ReReqest - bạn sẽ có cơ hội tốt hơn để có câu hỏi này được trả lời nếu bạn đăng câu hỏi đó dưới dạng câu hỏi riêng. Trong đó bạn có thể cung cấp liên kết quay lại câu hỏi này nếu bạn muốn. Đối với các chất câu hỏi - có vẻ OK nhưng tôi không có guru regex – Bostone

+1

Đó là một trong những tôi đang tìm kiếm. Nó thực sự phù hợp với tất cả mọi thứ ngoại trừ thanh. –

1

tôi đã có một danh sách tên tập tin, và tôi muốn loại trừ những người nhất định, với loại này hành vi (Ruby):.

files = [ 
    'mydir/states.rb',  # don't match these 
    'countries.rb', 
    'mydir/states_bkp.rb', # match these 
    'mydir/city_states.rb' 
] 
excluded = ['states', 'countries'] 

# set my_rgx here 

result = WankyAPI.filter(files, my_rgx) # I didn't write WankyAPI... 
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb'] 

Đây là giải pháp của tôi:

excluded_rgx = excluded.map{|e| e+'\.'}.join('|') 
my_rgx = /(^|\/)((?!#{excluded_rgx})[^\.\/]*)\.rb$/ 

giả định của tôi cho ứng dụng này:

  • Chuỗi được loại trừ là lúc bắt đầu của đầu vào, hoặc ngay sau dấu gạch chéo.
  • Các chuỗi được phép kết thúc bằng .rb.
  • Tên tệp được phép không có ký tự . trước số .rb.
3

Câu trả lời được chấp nhận là tốt nhưng thực sự là một công việc xung quanh việc thiếu toán tử phủ định biểu thức phụ đơn giản trong regexes. Đây là lý do tại sao grep --invert-match lần thoát. Vì vậy, trong * nixes, bạn có thể thực hiện kết quả mong muốn bằng cách sử dụng đường ống và một regex thứ hai.

grep 'something I want' | grep --invert-match 'but not these ones' 

Vẫn còn một cách giải quyết khác, nhưng có thể dễ nhớ hơn.

17

Giải pháp:

^(?!.*STRING1|.*STRING2|.*STRING3).*$ 

xxxxxx OK

xxxSTRING1xxx KO (được cho dù đó là mong muốn)

xxxSTRING2xxx KO (được cho dù đó là mong muốn)

xxxSTRING3xxx KO (là cho dù đó là mong muốn)

+1

cảm ơn, điều này đã cho tôi thêm thông tin tôi cần cho nhiều từ – RozzA

1

Tôi hy vọng để bổ sung cho câu trả lời

Khi Chris quy định Regex Tutorial là một nguồn lực tốt nhất cho việc học regex.

Tuy nhiên, nó thực sự tiêu tốn thời gian để đọc qua.

Tôi tạo một bảng xếp hạng để thuận tiện cho việc ghi nhớ.
[], (), {} dẫn đầu mỗi lớp dễ nhớ.

Regex = 
{'single_character': ['[]', '.', {'negate':'^'}], 
'capturing_group' : ['()', '|', '\\', 'backreferences and named group'], 
'repetition'  : ['{}', '*', '+', '?', 'greedy v.s. lazy'], 
'anchor'   : ['^', '\b', '$'], 
'non_printable' : ['\n', '\t', '\r', '\f', '\v'], 
'shorthand'  : ['\d', '\w', '\s'], 
} 
Các vấn đề liên quan