Biểu thức chính quy để khớp với một dòng không chứa từ


4294

Tôi biết có thể ghép một từ và sau đó đảo ngược các từ bằng cách sử dụng các công cụ khác (ví dụ grep -v). Tuy nhiên, có thể khớp các dòng không chứa một từ cụ thể, ví dụ: hedesử dụng cụm từ thông dụng không?

Đầu vào:

hoho
hihi
haha
hede

Mã số:

grep "<Regex for 'doesn't contain hede'>" input

Sản phẩm chất lượng:

hoho
hihi
haha

85
Có lẽ là một vài năm muộn, nhưng những gì sai với : ([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$)))*? Ý tưởng rất đơn giản. Tiếp tục khớp cho đến khi bạn thấy bắt đầu chuỗi không mong muốn, sau đó chỉ khớp trong các trường hợp N-1 trong đó chuỗi chưa hoàn thành (trong đó N là độ dài của chuỗi). Các trường hợp N-1 này là "h theo sau là không phải e", "anh ta theo sau là không phải d" và "hed theo sau là không phải e". Nếu bạn quản lý để vượt qua các trường hợp N-1 này, bạn đã thành công không khớp với chuỗi không mong muốn để bạn có thể bắt đầu tìm kiếm [^h]*lại
stevendesu

323
@stevendesu: hãy thử điều này với từ 'a-rất-rất-dài' hoặc thậm chí tốt hơn nửa câu. Vui chơi đánh máy. BTW, nó gần như không thể đọc được. Không biết về tác động hiệu suất.
Peter Schuetze

13
@PeterSchuetze: Chắc chắn nó không đẹp cho những từ rất dài, nhưng nó là một giải pháp khả thi và chính xác. Mặc dù tôi không chạy thử nghiệm về hiệu suất, tôi sẽ không tưởng tượng nó quá chậm vì hầu hết các quy tắc sau được bỏ qua cho đến khi bạn thấy một h (hoặc chữ cái đầu tiên của từ, câu, v.v.). Và bạn có thể dễ dàng tạo chuỗi regex cho các chuỗi dài bằng cách sử dụng phép nối lặp. Nếu nó hoạt động và có thể được tạo ra một cách nhanh chóng, mức độ dễ đọc có quan trọng không? Đó là những gì bình luận dành cho.
stevendesu

57
@stevendesu: tôi thậm chí muộn hơn, nhưng câu trả lời đó gần như hoàn toàn sai. đối với một điều, nó yêu cầu chủ đề phải chứa "h" mà nó không cần phải có, với nhiệm vụ là "các dòng khớp mà [không] không chứa một từ cụ thể". giả sử bạn có nghĩa là làm cho nhóm bên trong tùy chọn và mô hình được neo: ^([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$))?)*$ điều này không thành công khi các trường hợp "hede" được đi trước bởi các trường hợp một phần của "hede", chẳng hạn như trong "hhede".
jaytea

8
Câu hỏi này đã được thêm vào Câu hỏi thường gặp về Stack Overflow thường xuyên , trong phần "Regex-Fu nâng cao".
aliteralmind

Câu trả lời:


5894

Quan niệm rằng regex không hỗ trợ kết hợp nghịch đảo không hoàn toàn đúng. Bạn có thể bắt chước hành vi này bằng cách sử dụng các giao diện tiêu cực:

^((?!hede).)*$

Regex ở trên sẽ khớp với bất kỳ chuỗi hoặc dòng nào mà không ngắt dòng, không chứa chuỗi (phụ) 'hede'. Như đã đề cập, đây không phải là một cái gì đó regex là "tốt" ở (hoặc nên làm), nhưng vẫn còn, nó có thể.

Và nếu bạn cũng cần phải khớp các ký tự ngắt dòng, hãy sử dụng công cụ sửa đổi DOT-ALL (theo sau strong mẫu sau):

/^((?!hede).)*$/s

hoặc sử dụng nội tuyến:

/(?s)^((?!hede).)*$/

(trong đó các /.../dấu phân cách regex, nghĩa là không phải là một phần của mẫu)

Nếu công cụ sửa đổi DOT-ALL không khả dụng, bạn có thể bắt chước hành vi tương tự với lớp nhân vật [\s\S]:

/^((?!hede)[\s\S])*$/

Giải trình

Một chuỗi chỉ là một danh sách các nký tự. Trước và sau mỗi ký tự, có một chuỗi trống. Vì vậy, một danh sách các nký tự sẽ có n+1chuỗi rỗng. Hãy xem xét chuỗi "ABhedeCD":

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
S = e1 A e2 B e3 h e4 e e5 d e6 e e7 C e8 D e9
    └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘

index    0      1      2      3      4      5      6      7

trong đó các echuỗi là các chuỗi trống. Regex (?!hede).nhìn về phía trước để xem nếu không có chuỗi con "hede"nào được nhìn thấy, và nếu đó là trường hợp (vì vậy một cái gì đó khác được nhìn thấy), thì .(dấu chấm) sẽ khớp với bất kỳ ký tự nào ngoại trừ ngắt dòng. Nhìn xung quanh cũng được gọi là xác nhận độ rộng bằng không vì chúng không tiêu thụ bất kỳ ký tự nào. Họ chỉ khẳng định / xác nhận một cái gì đó.

Vì vậy, trong ví dụ của tôi, mọi chuỗi trống trước tiên được xác thực để xem nếu không có "hede"phía trước, trước khi một ký tự được sử dụng bởi .(dấu chấm). Regex (?!hede).sẽ làm điều đó chỉ một lần, do đó, nó được gói trong một nhóm và lặp lại 0 hoặc nhiều lần : ((?!hede).)*. Cuối cùng, đầu và cuối của đầu vào được neo để đảm bảo toàn bộ đầu vào được tiêu thụ:^((?!hede).)*$

Như bạn thấy, đầu vào "ABhedeCD"sẽ thất bại bởi vì trên e3, regex (?!hede)thất bại (có "hede" lên phía trước!).


26
Tôi sẽ không đi xa để nói rằng đây là một cái gì đó regex là xấu. Sự tiện lợi của giải pháp này là khá rõ ràng và hiệu suất đạt được so với tìm kiếm theo chương trình thường không quan trọng.
Archimaredes 3/03/2016

29
Nói một cách nghiêm túc loook-phía trước làm cho bạn biểu hiện thường xuyên không thường xuyên.
Peter K

55
@PeterK, chắc chắn, nhưng đây là SO, không phải MathOverflow hoặc CS-Stackexchange. Mọi người hỏi một câu hỏi ở đây thường tìm kiếm một câu trả lời thực tế. Hầu hết các thư viện hoặc công cụ (như grep, mà OP đề cập) với hỗ trợ regex đều có các tính năng khiến chúng không thường xuyên theo nghĩa lý thuyết.
Bart Kiers

19
@Bart Kiers, không có ý xúc phạm bạn trả lời, chỉ là sự lạm dụng thuật ngữ này làm tôi khó chịu một chút. Phần thực sự khó hiểu ở đây là các biểu thức chính quy theo nghĩa chặt chẽ có thể thực hiện rất nhiều những gì OP muốn, nhưng ngôn ngữ chung để viết chúng không cho phép điều đó, dẫn đến cách giải quyết (về mặt toán học) như cách nhìn. Xin vui lòng xem câu trả lời dưới đây và nhận xét của tôi ở đó cho cách (phù hợp về mặt lý thuyết) cách làm đúng. Không cần phải nói nó hoạt động nhanh hơn trên đầu vào lớn.
Peter K

17
Trong trường hợp bạn có bao giờ tự hỏi làm thế nào để làm điều này trong vim:^\(\(hede\)\@!.\)*$
baldrs

738

Lưu ý rằng giải pháp không bắt đầu với Giới hạn hede :

^(?!hede).*$

nói chung là hiệu quả hơn so với các giải pháp cho không chứa “Hede” :

^((?!hede).)*$

Các kiểm tra trước đây cho chỉ có một vị trí đầu tiên của chuỗi đầu vào, thay vì ở mọi vị trí.


5
Cảm ơn, tôi đã sử dụng nó để xác thực rằng chuỗi không chứa các chữ số ^ ((?! \ D {5,}).) *
Samih A

2
Xin chào! Tôi không thể sáng tác không kết thúc với regex "hede" . Bạn có thể giúp với nó?
Aleks Ya

1
@AleksYa: chỉ cần sử dụng phiên bản "chứa" và bao gồm neo cuối vào chuỗi tìm kiếm: thay đổi chuỗi thành "không khớp" từ "hede" thành "hede $"
Nyerguds

2
@AleksYa: phiên bản không kết thúc có thể được thực hiện bằng cách sử dụng giao diện phủ định là : (.*)(?<!hede)$. Phiên bản của @Nyerguds cũng sẽ hoạt động nhưng hoàn toàn bỏ lỡ điểm về hiệu suất mà câu trả lời đề cập.
thisismydesign

5
Tại sao có rất nhiều câu trả lời ^((?!hede).)*$? Nó không hiệu quả hơn để sử dụng ^(?!.*hede).*$? Nó cũng làm điều tương tự nhưng trong ít bước hơn
JackPRead

208

Nếu bạn chỉ sử dụng nó cho grep, bạn có thể sử dụng grep -v hedeđể có được tất cả các dòng không chứa hede.

ETA Oh, đọc lại câu hỏi, grep -vcó lẽ là những gì bạn có nghĩa là "tùy chọn công cụ".


22
Mẹo: để lọc dần dần những gì bạn không muốn: grep -v "hede" | grep -v "hihi" | ...Vân vân.
Olivier Lalonde

51
Hoặc chỉ sử dụng một quy trìnhgrep -v -e hede -e hihi -e ...
Olaf Dietsche

15
Hoặc chỉ grep -v "hede\|hihi":)
Putnik

2
Nếu bạn có nhiều mẫu mà bạn muốn lọc ra, đặt chúng trong một tập tin và sử dụnggrep -vf pattern_file file
codeforester

4
Hoặc đơn giản egrephoặc grep -Ev "hede|hihi|etc"để tránh sự trốn thoát vụng về.
Amit N Nikol

160

Câu trả lời:

^((?!hede).)*$

Giải trình:

^đầu chuỗi ( nhóm và chụp thành \ 1 (0 lần trở lên (khớp với số lượng nhiều nhất có thể)),
(?!nhìn về phía trước để xem nếu không có,

hede chuỗi của bạn,

)cuối nhìn về phía trước, .bất kỳ ký tự nào ngoại trừ \ n,
)*kết thúc \ 1 (Lưu ý: bởi vì bạn đang sử dụng bộ định lượng trên bản chụp này, chỉ có sự lặp lại LAST của mẫu đã chụp sẽ được lưu trong \ 1)
$trước \ \, và kết thúc chuỗi


14
tuyệt vời đã làm việc cho tôi trong văn bản cao siêu 2 bằng nhiều từ ' ^((?!DSAU_PW8882WEB2|DSAU_PW8884WEB2|DSAU_PW8884WEB).)*$'
Damodar Bashyal

3
@DamodarBashyal Tôi biết tôi đến khá muộn ở đây, nhưng bạn hoàn toàn có thể loại bỏ thuật ngữ thứ hai ở đó và bạn sẽ nhận được kết quả chính xác tương tự
forresthopkinsa

99

Các câu trả lời là hoàn toàn tốt, chỉ là một điểm học tập:

Biểu thức chính quy trong ý nghĩa của khoa học máy tính lý thuyết KHÔNG PHẢI làm điều đó như thế này. Đối với họ nó phải trông giống như thế này:

^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$) 

Điều này chỉ làm một trận đấu ĐẦY ĐỦ. Làm điều đó cho các trận đấu phụ thậm chí sẽ khó xử hơn.


1
Điều quan trọng cần lưu ý là điều này chỉ sử dụng các biểu thức chính quy POSIX.2 cơ bản và do đó terse dễ mang theo hơn khi PCRE không khả dụng.
Steve-o

5
Tôi đồng ý. Nhiều nếu không phải hầu hết các biểu thức chính quy không phải là ngôn ngữ thông thường và không thể được nhận ra bởi một automata hữu hạn.
ThomasMcLeod

@ThomasMcLeod, Hades32: Có phải trong phạm vi của bất kỳ ngôn ngữ thông thường có thể nào có thể nói ' không ' và ' ' cũng như ' hoặc ' của một biểu thức như ' (hede|Hihi)' không? (Đây có thể là một câu hỏi cho CS.)
James Haigh

7
@ John John: TÔI !!! Chà, không phải là regex thực tế mà là tài liệu tham khảo học thuật, cũng liên quan chặt chẽ đến độ phức tạp tính toán; PCRE về cơ bản không thể đảm bảo hiệu quả tương tự như các biểu thức thông thường POSIX.
James Haigh

4
Xin lỗi - câu trả lời này không hoạt động, nó sẽ khớp với hhehe và thậm chí khớp với hehe một phần (nửa sau)
Falco

60

Nếu bạn muốn kiểm tra regex chỉ thất bại nếu toàn bộ chuỗi khớp, thì sau đây sẽ hoạt động:

^(?!hede$).*

ví dụ: Nếu bạn muốn cho phép tất cả các giá trị ngoại trừ "foo" (nghĩa là "faggeroo", "barfoo" và "foobar" sẽ vượt qua, nhưng "foo" sẽ thất bại), hãy sử dụng: ^(?!foo$).*

Tất nhiên, nếu bạn đang kiểm tra sự bằng nhau chính xác , một giải pháp chung tốt hơn trong trường hợp này là kiểm tra sự bằng nhau của chuỗi, tức là

myStr !== 'foo'

Bạn thậm chí có thể đặt phủ định bên ngoài thử nghiệm nếu bạn cần bất kỳ tính năng regex nào (ở đây, độ nhạy cảm trường hợp và phạm vi khớp):

!/^[a-f]oo$/i.test(myStr)

Tuy nhiên, giải pháp regex ở đầu câu trả lời này có thể hữu ích, tuy nhiên, trong các tình huống yêu cầu kiểm tra regex dương tính (có lẽ bằng API).


những gì về dấu vết trắng? Ví dụ, nếu tôi muốn kiểm tra thất bại với chuỗi " hede "?
eagor

@eagor \schỉ thị khớp với một ký tự khoảng trắng duy nhất
Roy Tinker

cảm ơn, nhưng tôi đã không quản lý để cập nhật regex để thực hiện công việc này.
eagor

2
@eagor:^(?!\s*hede\s*$).*
Roy Tinker

52

FWIW, vì các ngôn ngữ thông thường (còn gọi là ngôn ngữ hợp lý) được đóng lại dưới sự bổ sung, nên luôn có thể tìm thấy một biểu thức chính quy (còn gọi là biểu thức hợp lý) phủ định một biểu thức khác. Nhưng không có nhiều công cụ thực hiện điều này.

Vcsn hỗ trợ toán tử này (mà nó biểu thị {c}, postfix).

Trước tiên, bạn xác định loại biểu của bạn: Nhãn là chữ cái ( lal_char) để chọn từ ađể zví dụ (xác định bảng chữ cái khi làm việc với bổ được, tất nhiên, rất quan trọng), và "giá trị" tính cho mỗi từ chỉ là một Boolean : truetừ được chấp nhận false, bị từ chối.

Trong Python:

In [5]: import vcsn
        c = vcsn.context('lal_char(a-z), b')
        c
Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}  𝔹

sau đó bạn nhập biểu thức của bạn:

In [6]: e = c.expression('(hede){c}'); e
Out[6]: (hede)^c

chuyển đổi biểu thức này thành máy tự động:

In [7]: a = e.automaton(); a

Máy tự động tương ứng

cuối cùng, chuyển đổi tự động này trở lại một biểu thức đơn giản.

In [8]: print(a.expression())
        \e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*

trong đó +thường được ký hiệu |, \ebiểu thị từ trống và [^]thường được viết .(bất kỳ ký tự nào). Vì vậy, với một chút viết lại ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*.

Bạn có thể xem ví dụ này ở đây , và thử Vcsn trực tuyến ở đó .


6
Đúng, nhưng xấu, và chỉ có thể làm được cho các bộ ký tự nhỏ. Bạn không muốn làm điều này với các chuỗi Unicode :-)
rebierpost

Có nhiều công cụ cho phép nó, một trong những công cụ ấn tượng nhất là Ragel . Ở đó, nó sẽ được viết dưới dạng (any * - ('hehe' any *)) cho trận đấu bắt đầu liên kết hoặc (any * - ('hehe' any *)) cho không được phân bổ.
Peter K

1
@reinierpost: tại sao nó xấu và vấn đề với unicode là gì? Tôi không thể đồng ý cả hai. (Tôi không có kinh nghiệm với vcsn, nhưng có DFA).
Peter K

3
@PedroGimeno Khi bạn thả neo, bạn có chắc chắn đặt regex này vào parens trước không? Mặt khác, các ưu tiên giữa các neo và |sẽ không chơi tốt. '^(()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*)$'.
akim

1
Tôi nghĩ rằng đáng để nhận xét rằng phương pháp này dành cho các dòng khớp không phải là từ 'hede', thay vì các dòng hơn là không chứa từ 'hede', đó là những gì OP yêu cầu. Xem câu trả lời của tôi cho sau này.
Pedro Gimeno

51

Đây là một lời giải thích tốt về lý do tại sao không dễ để phủ nhận một regex tùy ý. Tôi phải đồng ý với các câu trả lời khác, mặc dù: nếu đây là bất cứ điều gì khác ngoài một câu hỏi giả định, thì một regex không phải là lựa chọn đúng đắn ở đây.


10
Một số công cụ, và cụ thể là mysqldumpslow, chỉ cung cấp cách này để lọc dữ liệu, vì vậy trong trường hợp như vậy, tìm một biểu thức chính để thực hiện điều này là giải pháp tốt nhất ngoài việc viết lại công cụ (các bản vá khác nhau không được đưa vào bởi MySQL AB / Sun / Oracle.
FGM

1
Chính xác là hậu môn cho tình hình của tôi. Công cụ mẫu vận tốc sử dụng các biểu thức thông thường để quyết định khi nào nên áp dụng một phép biến đổi (thoát html) và tôi muốn nó luôn hoạt động NGOẠI TRỪ trong một tình huống.
Henno Vermeulen

1
Có gì thay thế? Ive chưa bao giờ gặp phải bất cứ điều gì có thể thực hiện khớp chuỗi chính xác ngoài regex. Nếu OP đang sử dụng ngôn ngữ lập trình, có thể có các công cụ khác có sẵn, nhưng nếu anh ấy / cô ấy đang sử dụng không viết mã, có lẽ không có lựa chọn nào khác.
kingfrito_5005

2
Một trong nhiều tình huống phi giả thuyết trong đó regex là lựa chọn khả dụng nhất: Tôi đang ở trong IDE (Android Studio) hiển thị đầu ra nhật ký và các công cụ lọc duy nhất được cung cấp là: chuỗi đơn giản và regex. Cố gắng làm điều này với các chuỗi đơn giản sẽ là một thất bại hoàn toàn.
LarsH

48

Với cái nhìn tiêu cực, biểu thức chính quy có thể khớp với một cái gì đó không chứa mẫu cụ thể. Điều này được trả lời và giải thích bởi Bart Kiers. Giải thích tuyệt vời!

Tuy nhiên, với câu trả lời của Bart Kiers, phần lookahead sẽ kiểm tra 1 đến 4 ký tự phía trước trong khi khớp với bất kỳ ký tự nào. Chúng ta có thể tránh điều này và để phần nhìn kiểm tra toàn bộ văn bản, đảm bảo không có 'hede', và sau đó phần bình thường (. *) Có thể ăn toàn bộ văn bản cùng một lúc.

Đây là regex được cải thiện:

/^(?!.*?hede).*$/

Lưu ý rằng bộ định lượng lười biếng (*?) Trong phần nhìn tiêu cực là tùy chọn, thay vào đó, bạn có thể sử dụng bộ định lượng tham lam (*), tùy thuộc vào dữ liệu của bạn: nếu 'hede' xuất hiện và trong nửa đầu của văn bản, bộ định lượng lười có thể Nhanh hơn; mặt khác, định lượng tham lam được nhanh hơn. Tuy nhiên, nếu 'hede' không xuất hiện, cả hai sẽ chậm như nhau.

Đây là mã demo .

Để biết thêm thông tin về lookahead, vui lòng xem bài viết tuyệt vời: Làm chủ Lookahead và Lookbehind .

Ngoài ra, vui lòng kiểm tra RegexGen.js , Trình tạo biểu thức chính quy JavaScript giúp xây dựng các biểu thức chính quy phức tạp. Với RegexGen.js, bạn có thể xây dựng biểu thức chính quy theo cách dễ đọc hơn:

var _ = regexGen;

var regex = _(
    _.startOfLine(),             
    _.anything().notContains(       // match anything that not contains:
        _.anything().lazy(), 'hede' //   zero or more chars that followed by 'hede',
                                    //   i.e., anything contains 'hede'
    ), 
    _.endOfLine()
);

3
vì vậy, chỉ cần kiểm tra xem chuỗi đã cho không chứa str1 và str2:^(?!.*(str1|str2)).*$
S.Serpooshan

1
Có, hoặc bạn có thể sử dụng bộ định lượng lười biếng : ^(?!.*?(?:str1|str2)).*$, tùy thuộc vào dữ liệu của bạn. Đã thêm ?:vì chúng tôi không cần phải nắm bắt nó.
amobiz

Đây là câu trả lời tốt nhất cho hệ số 10ms. Nếu bạn đã thêm mã jsfiddle và kết quả vào câu trả lời, mọi người có thể nhận thấy nó. Tôi tự hỏi tại sao phiên bản lười biếng lại nhanh hơn phiên bản tham lam khi không có hede. Họ có nên mất cùng một khoảng thời gian không?
dùng5389726598465

Có, họ mất cùng một khoảng thời gian vì cả hai đều kiểm tra toàn bộ văn bản.
amobiz

41

Điểm chuẩn

Tôi quyết định đánh giá một số Tùy chọn được trình bày và so sánh hiệu suất của chúng, cũng như sử dụng một số Tính năng mới. Điểm chuẩn trên .NET Regex Engine: http://regexhero.net/tester/

Văn bản điểm chuẩn:

7 dòng đầu tiên không khớp, vì chúng chứa Biểu thức được tìm kiếm, trong khi 7 dòng thấp hơn sẽ khớp!

Regex Hero is a real-time online Silverlight Regular Expression Tester.
XRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero
egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester.
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester.

Regex Her
egex Hero
egex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester.
Nobody is a real-time online Silverlight Regular Expression Tester.
Regex Her o egex Hero Regex  Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester.

Các kết quả:

Kết quả là số lần lặp mỗi giây là trung bình của 3 lần chạy - Số lớn hơn = Tốt hơn

01: ^((?!Regex Hero).)*$                    3.914   // Accepted Answer
02: ^(?:(?!Regex Hero).)*$                  5.034   // With Non-Capturing group
03: ^(?>[^R]+|R(?!egex Hero))*$             6.137   // Lookahead only on the right first letter
04: ^(?>(?:.*?Regex Hero)?)^.*$             7.426   // Match the word and check if you're still at linestart
05: ^(?(?=.*?Regex Hero)(?#fail)|.*)$       7.371   // Logic Branch: Find Regex Hero? match nothing, else anything

P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT))  ?????   // Logic Branch in Perl - Quick FAIL
P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ?????   // Direct COMMIT & FAIL in Perl

Vì .NET không hỗ trợ Động từ hành động (* FAIL, v.v.) nên tôi không thể kiểm tra các giải pháp P1 và P2.

Tóm lược:

Tôi đã thử kiểm tra hầu hết các giải pháp được đề xuất, một số Tối ưu hóa có thể cho một số từ nhất định. Ví dụ: nếu hai chữ cái đầu tiên của chuỗi tìm kiếm không giống nhau, câu trả lời 03 có thể được mở rộng để ^(?>[^R]+|R+(?!egex Hero))*$mang lại hiệu suất nhỏ.

Nhưng giải pháp nhanh nhất có thể đọc và hiệu suất nhanh nhất có vẻ là 05 bằng cách sử dụng câu lệnh có điều kiện hoặc 04 với bộ định lượng sở hữu. Tôi nghĩ rằng các giải pháp Perl nên nhanh hơn và dễ đọc hơn.


5
Bạn cũng nên có thời gian ^(?!.*hede). /// Ngoài ra, có thể tốt hơn để xếp hạng các biểu thức cho kho văn bản phù hợp và văn bản không phù hợp một cách riêng biệt bởi vì đó thường là trường hợp mà hầu hết các dòng khớp hoặc hầu hết các dòng không.
ikegami

32

Không phải regex, nhưng tôi đã thấy hợp lý và hữu ích khi sử dụng các greps nối tiếp với đường ống để loại bỏ tiếng ồn.

ví dụ. tìm kiếm một tập tin cấu hình apache mà không có tất cả các ý kiến-

grep -v '\#' /opt/lampp/etc/httpd.conf      # this gives all the non-comment lines

grep -v '\#' /opt/lampp/etc/httpd.conf |  grep -i dir

Logic của grep nối tiếp là (không phải bình luận) và (khớp với thư mục)


2
Tôi nghĩ anh ấy đang yêu cầu phiên bản regex củagrep -v
Angel.King.47

9
Điều này nguy hiểm. Cũng bỏ lỡ các dòng nhưgood_stuff #comment_stuff
Xavi Montero

29

với điều này, bạn tránh kiểm tra một cái nhìn trên mỗi vị trí:

/^(?:[^h]+|h++(?!ede))*+$/

tương đương với (đối với .net):

^(?>(?:[^h]+|h+(?!ede))*)$

Câu trả lời cũ:

/^(?>[^h]+|h+(?!ede))*$/

7
Điểm tốt; Tôi ngạc nhiên không ai đề cập đến phương pháp này trước đây. Tuy nhiên, regex cụ thể đó dễ bị quay lui thảm khốc khi áp dụng cho văn bản không phù hợp. Đây là cách tôi sẽ làm:/^[^h]*(?:h+(?!ede)[^h]*)*$/
Alan Moore

... Hoặc bạn chỉ có thể làm cho tất cả các bộ định lượng sở hữu. ;)
Alan Moore

@Alan Moore - Tôi cũng ngạc nhiên. Tôi thấy bình luận của bạn (và regex tốt nhất trong đống) chỉ ở đây sau khi đăng cùng mẫu này trong một câu trả lời dưới đây.
Ridgerunner

@ridgerunner, không phải là tho tốt nhất. Tôi đã thấy điểm chuẩn trong đó câu trả lời hàng đầu thực hiện tốt hơn. (Tôi đã rất ngạc nhiên về điều đó.)
Qtax

23

Bỏ qua (?:(?!hede).)* là tuyệt vời bởi vì nó có thể được neo.

^(?:(?!hede).)*$               # A line without hede

foo(?:(?!hede).)*bar           # foo followed by bar, without hede between them

Nhưng sau đây sẽ đủ trong trường hợp này:

^(?!.*hede)                    # A line without hede

Đơn giản hóa này đã sẵn sàng để có các mệnh đề "VÀ" được thêm vào:

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same

20

Đây là cách tôi làm:

^[^h]*(h(?!ede)[^h]*)*$

Chính xác và hiệu quả hơn các câu trả lời khác. Nó thực hiện kỹ thuật hiệu quả "unrolling-the-loop" của Friedl và yêu cầu quay lại ít hơn nhiều.


17

Nếu bạn muốn ghép một ký tự để phủ định một từ tương tự như phủ định lớp ký tự:

Ví dụ: một chuỗi:

<?
$str="aaa        bbb4      aaa     bbb7";
?>

Không được dùng:

<?
preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches);
?>

Sử dụng:

<?
preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches);
?>

Thông báo "(?!bbb)."không phải là lookbehind hay lookahead, ví dụ như lookc Hiện tại:

"(?=abc)abcde", "(?!abc)abcde"

3
Không có "giao diện" trong perl regrec's. Đây thực sự là một cái nhìn tiêu cực (tiền tố (?!). Tiền tố của lookahead tích cực sẽ là (?=trong khi các tiền tố lookbehind tương ứng sẽ (?<!(?<=tương ứng. Một cái nhìn có nghĩa là bạn đọc các ký tự tiếp theo (do đó đi trước trước) mà không tiêu thụ chúng. Một cái nhìn có nghĩa là bạn kiểm tra các ký tự đã được tiêu thụ.
Didier L

14

Một, theo tôi, biến thể dễ đọc hơn của câu trả lời hàng đầu:

^(?!.*hede)

Về cơ bản, "khớp ở đầu dòng khi và chỉ khi nó không có 'hede' trong đó" - vì vậy yêu cầu được dịch gần như trực tiếp thành regex.

Tất nhiên, có thể có nhiều yêu cầu thất bại:

^(?!.*(hede|hodo|hada))

Chi tiết: Neo ^ đảm bảo công cụ regex không thử lại khớp ở mọi vị trí trong chuỗi, khớp với mọi chuỗi.

^ Neo ở đầu có nghĩa là đại diện cho bắt đầu của dòng. Công cụ grep khớp với từng dòng một, trong bối cảnh bạn đang làm việc với một chuỗi nhiều dòng, bạn có thể sử dụng cờ "m":

/^(?!.*hede)/m # JavaScript syntax

hoặc là

(?m)^(?!.*hede) # Inline flag

Ví dụ tuyệt vời với nhiều phủ định.
Peter Parada

Một điểm khác biệt so với câu trả lời hàng đầu là điều này không khớp với bất cứ điều gì và phù hợp với toàn bộ dòng nếu không có "hede"
Z. Khullah

13

OP không chỉ định hoặc Tagbài đăng để chỉ ra bối cảnh (ngôn ngữ lập trình, trình soạn thảo, công cụ) mà Regex sẽ được sử dụng trong.

Đối với tôi, đôi khi tôi cần phải làm điều này trong khi chỉnh sửa một tệp bằng cách sử dụng Textpad.

Textpad hỗ trợ một số Regex, nhưng không hỗ trợ lookahead hoặc lookbehind, vì vậy phải mất một vài bước.

Nếu tôi đang tìm cách giữ lại tất cả các dòng KHÔNG chứa chuỗi hede, tôi sẽ làm như thế này:

1. Tìm kiếm / thay thế toàn bộ tập tin để thêm một "Thẻ" duy nhất vào đầu mỗi dòng có chứa bất kỳ văn bản nào.

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2. Xóa tất cả các dòng có chứa chuỗi hede(chuỗi thay thế trống):

    Search string:<@#-unique-#@>.*hede.*\n  
    Replace string:<nothing>  
    Replace-all  

3. Tại thời điểm này, tất cả các dòng còn lại KHÔNG chứa chuỗi hede. Xóa "Thẻ" duy nhất khỏi tất cả các dòng (chuỗi thay thế trống):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

Bây giờ bạn có văn bản gốc với tất cả các dòng chứa chuỗi hedebị loại bỏ.


Nếu tôi đang tìm cách làm gì đó khác chỉ với các dòng KHÔNG chứa chuỗi hede, tôi sẽ làm như thế này:

1. Tìm kiếm / thay thế toàn bộ tập tin để thêm một "Thẻ" duy nhất vào đầu mỗi dòng có chứa bất kỳ văn bản nào.

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2. Đối với tất cả các dòng có chứa chuỗi hede, hãy xóa "Thẻ" duy nhất:

    Search string:<@#-unique-#@>(.*hede)
    Replace string:\1  
    Replace-all  

3. Tại thời điểm này, tất cả các dòng bắt đầu bằng "Thẻ" duy nhất, KHÔNG chứa chuỗi hede. Bây giờ tôi có thể làm một cái gì đó khác chỉ với những dòng đó.

4. Khi tôi hoàn tất, tôi xóa "Thẻ" duy nhất khỏi tất cả các dòng (chuỗi thay thế trống):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

12

Vì không ai khác đưa ra câu trả lời trực tiếp cho câu hỏi đã được hỏi , tôi sẽ làm điều đó.

Câu trả lời là với POSIX grep, không thể đáp ứng yêu cầu này theo nghĩa đen:

grep "<Regex for 'doesn't contain hede'>" input

Lý do là POSIX grepchỉ được yêu cầu để hoạt động với Biểu thức chính quy cơ bản , đơn giản là không đủ mạnh để hoàn thành nhiệm vụ đó (chúng không có khả năng phân tích ngôn ngữ thông thường, vì thiếu xen kẽ và dấu ngoặc đơn).

Tuy nhiên, GNU grepthực hiện các phần mở rộng cho phép nó. Cụ thể, \|là toán tử xen kẽ trong việc triển khai BREs của GNU \(\)là dấu ngoặc đơn. Nếu công cụ biểu thức chính quy của bạn hỗ trợ xen kẽ, biểu thức ngoặc âm, dấu ngoặc đơn và ngôi sao Kleene và có thể neo vào đầu và cuối chuỗi, đó là tất cả những gì bạn cần cho phương pháp này. Tuy nhiên, lưu ý rằng các bộ phủ định [^ ... ]rất tiện lợi ngoài các bộ đó, bởi vì nếu không, bạn cần thay thế chúng bằng một biểu thức có dạng (a|b|c| ... )liệt kê mọi ký tự không có trong bộ, cực kỳ tẻ nhạt và quá dài, thậm chí còn hơn thế toàn bộ bộ ký tự là Unicode.

Với GNU grep, câu trả lời sẽ giống như:

grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" input

(được tìm thấy với Grail và một số tối ưu hóa khác được thực hiện bằng tay).

Bạn cũng có thể sử dụng một công cụ triển khai Biểu thức chính quy mở rộng , như egrep, để thoát khỏi dấu gạch chéo ngược:

egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" input

Đây là một kịch bản để kiểm tra nó (lưu ý rằng nó tạo ra một tệp testinput.txttrong thư mục hiện tại):

#!/bin/bash
REGEX="^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$"

# First four lines as in OP's testcase.
cat > testinput.txt <<EOF
hoho
hihi
haha
hede

h
he
ah
head
ahead
ahed
aheda
ahede
hhede
hehede
hedhede
hehehehehehedehehe
hedecidedthat
EOF
diff -s -u <(grep -v hede testinput.txt) <(grep "$REGEX" testinput.txt)

Trong hệ thống của tôi, nó in:

Files /dev/fd/63 and /dev/fd/62 are identical

như mong đợi.

Đối với những người quan tâm đến chi tiết, kỹ thuật được sử dụng là chuyển đổi biểu thức chính quy khớp với từ thành máy tự động hữu hạn, sau đó đảo ngược máy tự động bằng cách thay đổi mọi trạng thái chấp nhận thành không chấp nhận và ngược lại, sau đó chuyển đổi FA kết quả thành một biểu thức chính quy.

Cuối cùng, như mọi người đã lưu ý, nếu công cụ biểu thức chính quy của bạn hỗ trợ giao diện tiêu cực, điều đó sẽ đơn giản hóa công việc rất nhiều. Ví dụ: với GNU grep:

grep -P '^((?!hede).)*$' input

Cập nhật: Gần đây tôi đã tìm thấy thư viện FormTheory tuyệt vời của Kendall Hopkins , được viết bằng PHP, cung cấp một chức năng tương tự như Grail. Sử dụng nó và một trình giả lập do chính tôi viết, tôi đã có thể viết một trình tạo trực tuyến các biểu thức chính quy âm được cung cấp một cụm từ đầu vào (chỉ các ký tự chữ và số và dấu cách hiện được hỗ trợ): http://www.formauri.es/personal/ pgimeno / misc / không khớp-regex /

Đối với hedeđầu ra:

^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$

tương đương với ở trên.


11

Kể từ khi giới thiệu ruby-2.4.1, chúng ta có thể sử dụng Toán tử vắng mặt mới trong Biểu thức chính quy của Ruby

từ tài liệu chính thức

(?~abc) matches: "", "ab", "aab", "cccc", etc.
It doesn't match: "abc", "aabc", "ccccabc", etc.

Vì vậy, trong trường hợp của bạn ^(?~hede)$làm công việc cho bạn

2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)}
 => ["hoho", "hihi", "haha"]

9

Thông qua động từ PCRE (*SKIP)(*F)

^hede$(*SKIP)(*F)|^.*$

Điều này sẽ bỏ qua hoàn toàn dòng chứa chuỗi chính xác hedevà khớp với tất cả các dòng còn lại.

BẢN GIỚI THIỆU

Thi công các bộ phận:

Chúng ta hãy xem xét regex ở trên bằng cách chia nó thành hai phần.

  1. Phần trước |biểu tượng. Một phần không nên được kết hợp .

    ^hede$(*SKIP)(*F)
  2. Phần sau |biểu tượng. Một phần nên được kết hợp .

    ^.*$

PHẦN 1

Công cụ Regex sẽ bắt đầu thực hiện từ phần đầu tiên.

^hede$(*SKIP)(*F)

Giải trình:

  • ^ Khẳng định rằng chúng tôi đang bắt đầu.
  • hede Khớp chuỗi hede
  • $ Khẳng định rằng chúng tôi đang ở cuối dòng.

Vì vậy, dòng chứa chuỗi hedesẽ được khớp. Khi công cụ regex thấy động từ sau (*SKIP)(*F)( Lưu ý: Bạn có thể viết (*F)dưới dạng(*FAIL) ) động từ, nó bỏ qua và làm cho trận đấu thất bại. |được gọi là toán tử thay đổi hoặc toán tử OR được thêm vào bên cạnh động từ PCRE có nội dung khớp với tất cả các ranh giới tồn tại giữa mỗi và mọi ký tự trên tất cả các dòng ngoại trừ dòng chứa chuỗi chính xác hede. Xem bản demo tại đây . Đó là, nó cố gắng khớp các ký tự từ chuỗi còn lại. Bây giờ regex trong phần thứ hai sẽ được thực thi.

PHẦN 2

^.*$

Giải trình:

  • ^ Khẳng định rằng chúng tôi đang bắt đầu. tức là, nó phù hợp với tất cả các dòng bắt đầu ngoại trừ một trong hededòng. Xem bản demo tại đây .
  • .*Trong chế độ Đa tuyến, .sẽ khớp với bất kỳ ký tự nào ngoại trừ các ký tự trả về dòng mới hoặc dòng vận chuyển. Và *sẽ lặp lại ký tự trước 0 hoặc nhiều lần. Vì vậy, .*sẽ phù hợp với toàn bộ dòng. Xem bản demo tại đây .

    Hey tại sao bạn thêm. * Thay vì. +?

    Bởi vì .*sẽ khớp với một dòng trống nhưng .+sẽ không khớp với một khoảng trống. Chúng tôi muốn khớp tất cả các dòng ngoại trừ hede, có thể có khả năng các dòng trống cũng có trong đầu vào. vì vậy bạn phải sử dụng .*thay vì .+. .+sẽ lặp lại nhân vật trước một hoặc nhiều lần. Xem .*phù hợp với một dòng trống ở đây .

  • $ Kết thúc neo dòng là không cần thiết ở đây.


7

Có thể duy trì nhiều hơn hai regex trong mã của bạn, một để thực hiện khớp đầu tiên và sau đó nếu nó khớp chạy regex thứ hai để kiểm tra các trường hợp ngoại lệ bạn muốn chặn, ví dụ như vậy ^.*(hede).*có logic phù hợp trong mã của bạn.

OK, tôi thừa nhận đây không thực sự là một câu trả lời cho câu hỏi được đăng và nó cũng có thể sử dụng xử lý nhiều hơn một chút so với một regex duy nhất. Nhưng đối với các nhà phát triển đến đây để tìm kiếm một sửa chữa khẩn cấp nhanh chóng cho một trường hợp ngoại lệ thì không nên bỏ qua giải pháp này.


6

Một tùy chọn khác là để thêm một cái nhìn tích cực về phía trước và kiểm tra xem hehecó ở bất kỳ vị trí nào trong dòng đầu vào không, sau đó chúng tôi sẽ phủ nhận điều đó, với một biểu thức tương tự như:

^(?!(?=.*\bhede\b)).*$

với ranh giới từ.


Biểu thức được giải thích ở bảng trên cùng bên phải của regex101.com , nếu bạn muốn khám phá / đơn giản hóa / sửa đổi nó và trong liên kết này , bạn có thể xem cách nó phù hợp với một số đầu vào mẫu, nếu bạn muốn.


Mạch RegEx

jex.im hình dung các biểu thức thông thường:

nhập mô tả hình ảnh ở đây


5

Các TXR Ngôn ngữ hỗ trợ phủ regex.

$ txr -c '@(repeat)
@{nothede /~hede/}
@(do (put-line nothede))
@(end)'  Input

Một ví dụ phức tạp hơn: khớp tất cả các dòng bắt đầu avà kết thúc bằng z, nhưng không chứa chuỗi con hede:

$ txr -c '@(repeat)
@{nothede /a.*z&~.*hede.*/}
@(do (put-line nothede))
@(end)' -
az         <- echoed
az
abcz       <- echoed
abcz
abhederz   <- not echoed; contains hede
ahedez     <- not echoed; contains hede
ace        <- not echoed; does not end in z
ahedz      <- echoed
ahedz

Regex phủ định không đặc biệt hữu ích nhưng khi bạn cũng có giao lộ, mọi thứ trở nên thú vị, vì bạn có một tập hợp đầy đủ các thao tác boolean: bạn có thể diễn tả "tập hợp khớp với điều này, ngoại trừ những thứ phù hợp với điều đó".


Lưu ý rằng đó cũng là giải pháp cho regex dựa trên ElasticSearch Lucene.
Wiktor Stribiżew

4

Các chức năng dưới đây sẽ giúp bạn có được đầu ra mong muốn của bạn

<?PHP
      function removePrepositions($text){

            $propositions=array('/\bfor\b/i','/\bthe\b/i'); 

            if( count($propositions) > 0 ) {
                foreach($propositions as $exceptionPhrase) {
                    $text = preg_replace($exceptionPhrase, '', trim($text));

                }
            $retval = trim($text);

            }
        return $retval;
    }


?>

2

^ ((?! hede).) * $ là một giải pháp tao nhã, ngoại trừ việc nó tiêu thụ các ký tự bạn sẽ không thể kết hợp nó với các tiêu chí khác. Chẳng hạn, giả sử bạn muốn kiểm tra sự không có mặt của "hede" và sự hiện diện của "haha". Giải pháp này sẽ hoạt động vì nó sẽ không tiêu thụ các ký tự:

^ (?!. \ Bhede \ b) (? =. \ Bhaha \ b)


1

Cách sử dụng các động từ điều khiển quay lui của PCRE để khớp với một dòng không chứa từ

Đây là một phương pháp mà tôi chưa từng thấy trước đây:

/.*hede(*COMMIT)^|/

Làm thế nào nó hoạt động

Đầu tiên, nó cố gắng tìm "hede" ở đâu đó trong dòng. Nếu thành công, tại thời điểm này,(*COMMIT) cho động cơ biết, không những không quay lại trong trường hợp xảy ra lỗi, mà còn không cố gắng thực hiện bất kỳ kết hợp nào nữa trong trường hợp đó. Sau đó, chúng tôi cố gắng khớp một cái gì đó không thể phù hợp (trong trường hợp này, ^).

Nếu một dòng không chứa "hede" thì thay thế thứ hai, một mẫu con trống, khớp thành công với chuỗi chủ đề.

Phương pháp này không hiệu quả hơn một cái nhìn tiêu cực, nhưng tôi đoán rằng tôi sẽ ném nó vào đây trong trường hợp ai đó thấy nó tiện lợi và tìm thấy cách sử dụng nó cho các ứng dụng khác thú vị hơn.


0

Một giải pháp đơn giản hơn là sử dụng toán tử không !

Câu lệnh if của bạn sẽ cần khớp "chứa" và không khớp "loại trừ".

var contains = /abc/;
var excludes =/hede/;

if(string.match(contains) && !(string.match(excludes))){  //proceed...

Tôi tin rằng các nhà thiết kế của RegEx đã lường trước việc sử dụng không phải các nhà khai thác.


0

Có thể bạn sẽ tìm thấy điều này trên Google trong khi cố gắng viết một biểu thức chính quy có thể khớp với các phân đoạn của một dòng (trái ngược với toàn bộ các dòng) không chứa chuỗi con. Làm phiền tôi một lúc để tìm hiểu, vì vậy tôi sẽ chia sẻ:

Cho một chuỗi: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

Tôi muốn khớp <span>các thẻ không chứa chuỗi con "xấu".

/<span(?:(?!bad).)*?>sẽ phù hợp <span class=\"good\"><span class=\"ugly\">.

Lưu ý rằng có hai bộ (lớp) dấu ngoặc đơn:

  • Cái trong cùng là dành cho cái nhìn tiêu cực (nó không phải là một nhóm bắt giữ)
  • Lớp ngoài cùng được Ruby diễn giải là nhóm bắt giữ nhưng chúng tôi không muốn nó là nhóm bắt giữ, vì vậy tôi đã thêm vào: lúc bắt đầu và nó không còn được hiểu là nhóm bắt giữ.

Bản trình diễn trong Ruby:

s = '<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>'
s.scan(/<span(?:(?!bad).)*?>/)
# => ["<span class=\"good\">", "<span class=\"ugly\">"]

0

Với ConyEdit , bạn có thể sử dụng dòng lệnh cc.gl !/hede/để nhận các dòng không chứa kết hợp regex hoặc sử dụng dòng lệnh cc.dl /hede/để xóa các dòng có chứa kết hợp regex. Họ có kết quả tương tự.


0

Tôi muốn thêm một ví dụ khác nếu bạn đang cố gắng khớp toàn bộ một dòng có chứa chuỗi X , nhưng cũng không chứa chuỗi Y .

Ví dụ: giả sử chúng tôi muốn kiểm tra xem URL / chuỗi của chúng tôi có chứa " món ngon " hay không, miễn là nó không chứa " sô cô la " ở bất cứ đâu.

Mẫu regex này sẽ hoạt động (cũng hoạt động trong JavaScript)

^(?=.*?tasty-treats)((?!chocolate).)*$

(ví dụ toàn cầu, cờ đa dòng)

Ví dụ tương tác: https://regexr.com/53gv4

Diêm

(Những url này chứa "món ngon" và cũng không chứa "sô cô la")

  • example.com/tasty-turr/strawberry-ice-cream
  • example.com/desserts/tasty-turr/banana-pudding
  • example.com/tasty-turr-overview

Không phù hợp với

(Những url này có chứa "sô cô la" ở đâu đó - vì vậy chúng sẽ không khớp với nhau mặc dù chúng có chứa "món ngon"

  • example.com/tasty-turr/chatioate-dding
  • example.com/home-cooking/oven-roOK-chicken
  • example.com/tasty-turr/banana-chocolate-fudge
  • example.com/desserts/chocolate/tasty-turr
  • example.com/chocolate/tasty-turr/desserts
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.