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

4493
knaser 2009-01-02 21:30.

Tôi biết có thể ghép một từ và sau đó đảo ngược các kết quả phù hợp bằng các công cụ khác (ví dụ grep -v:). Tuy nhiên, liệu có thể so 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ã:

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

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

hoho
hihi
haha

30 answers

6170
Bart Kiers 2009-01-02 23:55.

Quan điểm cho rằng regex không hỗ trợ kết hợp nghịch đảo là 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 cách nhìn tiêu cực:

^((?!hede).)*$

Regex ở trên sẽ khớp với bất kỳ chuỗi nào hoặc dòng nào không có dấu 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 đối sánh các ký tự ngắt dòng, hãy sử dụng công cụ sửa đổi DOT-ALL (dấu cuối strong mẫu sau):

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

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

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

(trong đó /.../là các dấu phân cách regex, tức 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 trố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 đó elà 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 trường hợp đó xảy ra (vì vậy thứ 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ừ dấu ngắt dòng. Chế độ xem còn được gọi là xác nhận không có chiều rộng vì chúng không sử dụng 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 đều được xác thực đầu tiên để xem liệu không có dòng nào "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 đó một lần duy nhất, vì vậy nó được bọc trong một nhóm, và lặp đi lặp lại không hay nhiều lần: ((?!hede).)*. Cuối cùng, đầu vào và cuối đầu vào được cố định để đả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!).

774
FireCoding 2011-03-17 18:21.

Lưu ý rằng giải pháp không bắt đầu bằng "hede" :

^(?!hede).*$

nói chung là hiệu quả hơn nhiều so với giải pháp không chứa "hede" :

^((?!hede).)*$

Trước đây chỉ kiểm tra “hede” ở vị trí đầu tiên của chuỗi đầu vào, thay vì ở mọi vị trí.

213
Athena 2009-01-02 21:41.

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

ETA Ồ, đọc lại câu hỏi, grep -vcó lẽ ý bạn là "tùy chọn công cụ".

169
Jessica 2014-05-11 06:36.

Câu trả lời:

^((?!hede).)*$

Giải trình:

^phần đầu của 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ể)),
(?!hãy nhìn về phía trước để xem nếu không có,

hede chuỗi của bạn,

)cuối nhìn trước, .bất kỳ ký tự nào ngoại trừ \ n,
)*cuối \ 1 (Lưu ý: vì bạn đang sử dụng bộ định lượng trên bản chụp này, chỉ phần lặp lại CUỐI CÙNG của mẫu đã chụp mới được lưu trữ trong \ 1)
$trước \ n tùy chọn, và cuối chuỗi

104
Hades32 2011-09-03 05:53.

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

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

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

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

64
Roy Tinker 2013-01-04 11:22.

Nếu bạn muốn kiểm tra regex chỉ không thành công nếu toàn bộ chuỗi khớp, cách sau 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" (tức là "foofoo", "barfoo" và "foobar" sẽ vượt qua, nhưng "foo" sẽ không thành công), hãy sử dụng: ^(?!foo$).*

Tất nhiên, nếu bạn đang kiểm tra sự bình đẳng chính xác , giải pháp chung tốt hơn trong trường hợp này là kiểm tra sự bình đẳng 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, phân biệt chữ hoa chữ thường và đối sánh phạm vi):

!/^[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 trong các tình huống yêu cầu kiểm tra regex dương tính (có thể bằng API).

57
akim 2015-08-05 21:02.

FWIW, vì các ngôn ngữ thông thường (hay còn gọi là ngôn ngữ hợp lý) được đóng dưới sự bổ sung, nên luôn có thể tìm thấy một biểu thức chính quy (hay 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 (nó ký hiệu là {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 mình:

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

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

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

cuối cùng, chuyển đổi automaton 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[^]))))[^]*

nơi +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 ở đó .

56
Josh Lee 2009-01-02 22:03.

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

51
amobiz 2014-07-15 08:21.

Với trang đầu phủ định, biểu thức chính quy có thể khớp với nội dung nào đó 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. Lời 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 từ 1 đến 4 ký tự phía trước trong khi khớp với bất kỳ ký tự đơn lẻ nào. Chúng ta có thể tránh điều này và để phần nhìn trước 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 tiến:

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

Lưu ý rằng bộ định lượng lười biếng (*?) Trong phần tiêu cực của văn bản là tùy chọn, bạn có thể sử dụng bộ định lượng tham lam (*) để thay thế, tùy thuộc vào dữ liệu của bạn: nếu 'hede' xuất hiện và ở nửa đầu của văn bản, bộ định lượng lười biếng có thể Nhanh hơn; nếu không, bộ định lượng tham lam sẽ 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 xem RegexGen.js , một Trình tạo biểu thức chính quy JavaScript giúp tạo 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 regex 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()
);
43
Falco 2014-08-14 04:58.

Điểm chuẩn

Tôi quyết định đánh giá một số Tùy chọn đã 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. Đo đ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 được khớp, vì chúng chứa Biểu thức được tìm kiếm, trong khi 7 dòng dưới phải 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 lại 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 đã cố gắng 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ể thực hiện được 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))*$dẫn đến một mức tăng hiệu suất nhỏ.

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

33
kiwalk 2011-02-24 04:00.

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

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

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 nhận xét) và (khớp với dir)

30
Casimir et Hippolyte 2013-04-14 17:04.

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

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

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

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

Câu trả lời cũ:

/^(?>[^h]+|h+(?!ede))*$/
24
ikegami 2016-08-23 14:03.

Đã nói ở trên (?:(?!hede).)*là rất tốt vì nó có thể được neo.

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

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

Nhưng những điều sau đây sẽ đủ trong trường hợp này:

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

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

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same
21
ridgerunner 2013-12-20 17:03.

Đây là cách tôi sẽ làm điều đó:

^[^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 ít backtracking hơn nhiều.

18
diyism 2012-03-23 21:24.

Nếu bạn muốn so khớ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à cái nhìn sau hay cái nhìn trước, mà là cái nhìn theo dòng điện, ví dụ:

"(?=abc)abcde", "(?!abc)abcde"
18
Dannie P 2018-11-25 08:26.

An, trong opinon của 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 nếu 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 sang regex.

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

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

Chi tiết: ^ anchor đảm bảo công cụ regex không thử lại kết quả khớp ở mọi vị trí trong chuỗi, điều này sẽ khớp với mọi chuỗi.

Dấu ^ neo ở đầu có nghĩa là đại diện cho phần đầu của dòng. Công cụ grep khớp từng dòng một, trong bối cảnh bạn đang làm việc với 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
14
Kevin Fegan 2013-04-27 12:28.

OP không chỉ định hoặc Tagbài đăng để chỉ ra ngữ 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 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 cần thực hiện 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 để thêm một "Thẻ" duy nhất vào đầu mỗi dòng 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 có chứa chuỗi hedeđã bị loại bỏ.


Nếu tôi đang tìm cách Làm điều gì đó khác với chỉ những 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 để thêm một "Thẻ" duy nhất vào đầu mỗi dòng 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 Điều gì đó khác của tôi 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  
14
Pedro Gimeno 2016-12-07 11:24.

Vì không ai khác đưa ra câu trả lời trực tiếp cho câu hỏi được đặt ra nên 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 đúng nghĩa đen:

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

Lý do là POSIX grepchỉ được yêu cầu để làm việc 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 cú pháp tất cả các ngôn ngữ thông thường, vì thiếu sự thay thế).

Tuy nhiên , GNU grepthực hiện các phần mở rộng cho phép nó. Đặc biệt, \|là nhà điều hành luân phiên trong việc thực hiện BREs của GNU. Nếu công cụ biểu thức chính quy của bạn hỗ trợ xen kẽ, dấu ngoặc đơn và dấu 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 cách tiếp cận này. Tuy nhiên, lưu ý rằng bộ phủ định [^ ... ]rất thuận tiện khi bổ sung các bộ đó, 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ộ, điều này cực kỳ tẻ nhạt và quá dài, thậm chí còn hơn nếu toàn bộ bộ ký tự là Unicode.

Nhờ lý thuyết ngôn ngữ chính thức, chúng ta có thể hiểu được cách diễn đạt như vậy. Với GNU grep, câu trả lời sẽ là:

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 , chẳng hạn như egrep, để loại bỏ các 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 tập lệnh để 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). Một số biểu thức được trình bày không thành công trong bài kiểm tra này.

#!/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ột tự động hữu hạn, sau đó đảo ngược tự động hóa 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ả trở lại một biểu thức chính quy.

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ợ trang đầu phủ định, thì biểu thức chính quy sẽ đơn giản hơn nhiều. Ví dụ, với GNU grep:

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

Tuy nhiên, cách tiếp cận này có nhược điểm là nó yêu cầu một công cụ biểu thức chính quy backtracking. Điều này làm cho nó không phù hợp trong các cài đặt đang sử dụng công cụ biểu thức chính quy an toàn như RE2 , đó là một lý do để thích cách tiếp cận được tạo trong một số trường hợp.

Sử dụng thư viện FormalTheory 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 và một trình đơn giản hóa 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 phủ định với một cụm từ đầu vào (chỉ chữ và số và dấu cách ký tự hiện được hỗ trợ):http://www.formauri.es/personal/pgimeno/misc/non-match-regex/

Đối với hedenó, kết quả đầ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.

12
aelor 2017-03-24 03:42.

Kể từ khi ruby-2.4.1 ra đời, 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)$, công việc cho bạn

2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)}
 => ["hoho", "hihi", "haha"]
10
Avinash Raj 2014-10-09 21:00.

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

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

Điều này sẽ hoàn toàn bỏ qua 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 |ký hiệu. Một phần không nên được khớp với nhau .

    ^hede$(*SKIP)(*F)
    
  2. Phần sau |ký hiệu. Một phần nên được phù hợp .

    ^.*$
    

PHẦN 1

Regex engine 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 với 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 nhìn thấy động từ sau (*SKIP)(*F)( Lưu ý: Bạn có thể viết (*F)(*FAIL) ), nó sẽ bỏ qua và làm cho kết quả không khớp. |được gọi là thay đổi hoặc toán tử OR logic được thêm vào bên cạnh động từ PCRE mà inturn 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ó khớp với tất cả các dòng bắt đầu ngoại trừ một hededòng trong dòng. Xem bản demo tại đây .
  • .*Trong chế độ Nhiều dòng, .sẽ khớp với bất kỳ ký tự nào ngoại trừ ký tự xuống dòng hoặc ký tự xuống dòng. Và *sẽ lặp lại ký tự trước đó không 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 .

    Này, tại sao bạn lại 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ó các dòng trống trong đầu vào. vì vậy bạn phải sử dụng .*thay vì .+. .+sẽ lặp lại ký tự trước đó một hoặc nhiều lần. Xem .*phù hợp với một dòng trống ở đây .

  • $ Không cần thiết phải neo cuối dòng ở đây.

9
Emma 2019-08-01 16:36.

Một tùy chọn khác là để thêm một cái nhìn tích cực và kiểm tra xem hedecó ở bất kỳ đâu trong dòng nhập hay không, thì chúng tôi sẽ phủ định đ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 trên bảng điều khiển 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 biểu thức và trong liên kết này , bạn có thể xem nó sẽ khớp như thế nào với một số đầu vào mẫu, nếu bạn muốn.


Mạch RegEx

jex.im trực quan hóa các biểu thức chính quy:

8
andrew pate 2015-02-19 01:45.

Nó có thể dễ bảo trì hơn đối với 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, hãy chạy regex thứ hai để kiểm tra các trường hợp ngoại lệ mà bạn muốn chặn, ví dụ như ^.*(hede).*sau đó có logic thích hợp trong mã của bạn.

OK, tôi thừa nhận đây không thực sự là câu trả lời cho câu hỏi đã đăng đã đăng và nó cũng có thể sử dụng nhiều xử lý 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 bản sửa lỗi 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
Kaz 2014-06-25 15:23.

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: so khớp tất cả các dòng bắt đầu bằng 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

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

4
Daniel Nyamasyo 2016-12-21 18:55.

Chức năng dưới đây sẽ giúp bạn có được đầu ra mong muố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
cloudhopperpilot 2019-03-27 02:21.

^((?!hede).)*$là một giải pháp thanh lịch, ngoại trừ vì nó sử dụng các ký tự nên bạn sẽ không thể kết hợp nó với các tiêu chí khác. Ví dụ: giả sử bạn muốn kiểm tra sự không hiện diện 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 sử dụng các ký tự:

^(?!.*\bhede\b)(?=.*\bhaha\b) 
1
jaytea 2017-10-12 00:12.

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

Đây là một phương pháp mà tôi chưa từng thấy được sử dụng 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)yêu cầu động cơ không những không quay lại trong trường hợp bị lỗi, mà còn không cố gắng kết hợp thêm trong trường hợp đó. Sau đó, chúng tôi cố gắng kết hợp một cái gì đó không thể khớp (trong trường hợp này là ^).

Nếu một dòng không chứa "hede" thì dòng thay thế thứ hai, một dòng phụ 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 nghĩ 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 nó sử dụng cho các ứng dụng khác, thú vị hơn.

1
Matthew Rideout 2020-04-29 08:53.

Tôi muốn thêm một ví dụ khác vì nếu bạn đang cố gắng để phù hợp với toàn bộ một dòng có chứa chuỗi X , nhưng không còn 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 kỳ đâu.

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

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

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

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

Diêm

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

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

Không phù hợp với

(Các url này có chứa "sô cô la" ở đâu đó - vì vậy chúng sẽ không khớp ngay cả khi chúng chứa "món ngon")

  • example.com/tasty-treats/chocolate-cake
  • example.com/home-cooking/oven-roasted-chicken
  • example.com/tasty-treats/banana-chocolate-fudge
  • example.com/desserts/chocolate/tasty-treats
  • example.com/chocolate/tasty-treats/desserts
1
Anas R. 2020-06-16 01:02.

Miễn là bạn đang xử lý các dòng , chỉ cần đánh dấu các kết quả phù hợp tiêu cực và nhắm mục tiêu phần còn lại .

Trên thực tế, tôi sử dụng thủ thuật này với sed vì ^((?!hede).)*$ngoại hình không được hỗ trợ bởi nó.

Để có đầu ra mong muốn

  1. Đánh dấu kết hợp phủ định: (ví dụ: dòng với hede), sử dụng một ký tự không có trong toàn bộ văn bản. Một biểu tượng cảm xúc có thể là một lựa chọn tốt cho mục đích này.

    s/(.*hede)/🔒\1/g
    
  2. Nhắm mục tiêu phần còn lại (các chuỗi không được đánh dấu: ví dụ như các dòng không có hede). Giả sử bạn chỉ muốn giữ lại mục tiêu và xóa phần còn lại (như bạn muốn):

    s/^🔒.*//g
    

Để hiểu rõ hơn

Giả sử bạn muốn xóa mục tiêu :

  1. Đánh dấu kết hợp phủ định: (ví dụ: dòng với hede), sử dụng một ký tự không có trong toàn bộ văn bản. Một biểu tượng cảm xúc có thể là một lựa chọn tốt cho mục đích này.

    s/(.*hede)/🔒\1/g
    
  2. Nhắm mục tiêu phần còn lại (các chuỗi không được đánh dấu: ví dụ như các dòng không có hede). Giả sử bạn muốn xóa mục tiêu :

    s/^[^🔒].*//g
    
  3. Xóa dấu:

    s/🔒//g
    
0
user1691651-John 2016-09-14 03:52.

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

Câu lệnh if của bạn sẽ cần phải khớp với "chứa" và không khớp với "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 đã đoán trước được việc sử dụng không phải toán tử.

0
BrunoFacca 2018-04-26 08:15.

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 regex có thể khớp 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. Yêu cầu tôi một thời gian để tìm ra, 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 so 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 dành cho cái nhìn tiêu cực (nó không phải là nhóm chụp)
  • Ngoài cùng được Ruby hiểu là nhóm bắt nhưng chúng tôi không muốn nó là nhóm bắt, 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 nữa.

Demo 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\">"]

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Trong Saturday Night Live, The Bachelor is Bland và Tina Fey trở lại với vai 'Crazy' Sarah Palin

Trong Saturday Night Live, The Bachelor is Bland và Tina Fey trở lại với vai 'Crazy' Sarah Palin

Sau khi Sarah Palin tán thành Donald Trump vào đầu tuần này, gần như không thể tránh khỏi việc Tina Fey sẽ trở lại Saturday Night Live để thăm lại ấn tượng Palin cổ điển của cô. Và Fey chắc chắn đã không làm thất vọng, cô ấy đã đưa ra một lời khen ngợi không hề nhẹ về bài phát biểu chứng thực Iowa quanh co và khó hiểu của Palin trong khi Trump của Darrell Hammond đưa ra bình luận xuyên suốt.

Đây có phải là sự khởi đầu cho sự kết thúc của việc giam giữ Brittney Griner?

Đây có phải là sự khởi đầu cho sự kết thúc của việc giam giữ Brittney Griner?

Brittney Griner (r.) Ngay từ đầu, thân phận của Brittney Griner đã là tình huống con tin Mỹ độc nhất trong lịch sử hiện đại.

Tom Brady là bộ tứ vệ đầu tiên cuối cùng có thể giúp Julio Jones có hơn 10 lần chạm bóng trong một mùa giải

Tom Brady là bộ tứ vệ đầu tiên cuối cùng có thể giúp Julio Jones có hơn 10 lần chạm bóng trong một mùa giải

Chúng ta có thể thấy nhiều hơn nữa về một Julio Jones khỏe mạnh trong khu vực cuối năm nay. John Parker Wilson, Greg McElroy, A.

Đó phải là Đức

Đó phải là Đức

Đối với đội tuyển Anh, không có kẻ thủ ác nào lớn hơn Hầu hết các cổ động viên Anh, nếu không muốn nói là tất cả, hẳn sẽ phải gật gù khi tiếng còi mãn cuộc của trận bán kết lượt về W Euro 2022 vang lên. Bởi vì nó báo hiệu rằng Đức sẽ chờ đợi ở Wembley trong trận chung kết với Anh và là điều duy nhất giữa Anh và chiếc cúp lớn đầu tiên của đội tuyển nữ.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Đường băng hạ cánh

Đường băng hạ cánh

Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Language