Một Regex sẽ không bao giờ được kết hợp bởi bất cứ điều gì


131

Điều này nghe có vẻ như là một câu hỏi ngu ngốc, nhưng tôi đã có một cuộc nói chuyện dài với một số nhà phát triển đồng nghiệp của tôi và nó nghe có vẻ như là một điều thú vị để nghĩ về.

Vì thế; suy nghĩ của bạn - Regex trông như thế nào, sẽ không bao giờ được khớp với bất kỳ chuỗi nào!

Chỉnh sửa : Tại sao tôi muốn điều này? Chà, thứ nhất là vì tôi thấy thú vị khi nghĩ về một biểu hiện như vậy và thứ hai là vì tôi cần nó cho một kịch bản.

Trong kịch bản đó, tôi định nghĩa một từ điển là Dictionary<string, Regex>. Điều này chứa, như bạn thấy, một chuỗi và một biểu thức.

Dựa trên từ điển đó, tôi tạo ra các phương thức mà tất cả đều sử dụng từ điển này như chỉ tham khảo về cách chúng nên thực hiện công việc của chúng, một trong số chúng khớp với các biểu thức so với tệp logfile được phân tích cú pháp.

Nếu một biểu thức được khớp, một biểu thức khác Dictionary<string, long>được thêm vào một giá trị được biểu thức trả về. Vì vậy, để bắt bất kỳ thông điệp tường trình nào không khớp với một biểu thức trong từ điển, tôi đã tạo một nhóm mới gọi là "không xác định".

Đối với nhóm này, mọi thứ không khớp với bất cứ thứ gì khác được thêm vào. Nhưng để ngăn chặn sự "không xác định" biểu hiện không khớp (tình cờ) một thông điệp tường trình, tôi đã phải tạo một biểu thức chắc chắn không bao giờ khớp, bất kể tôi đưa ra chuỗi nào.

Vì vậy, có bạn có lý do của tôi cho "không phải là một câu hỏi thực sự" ...


1
Lưu ý rằng rất khó để chứng minh một tiêu cực.
Lasse V. Karlsen

5
Hấp dẫn. Bạn sẽ sử dụng regex như vậy ở đâu?
Charlie Salts

1
Tôi sẽ lưu ý ở đây cho hồ sơ rằng nhiều ý kiến ​​ở trên và câu trả lời cho câu hỏi này, ban đầu là từ stackoverflow.com/questions/1845078/ Lỗi mà tôi đã hỏi. Marc Gravell đã hợp nhất chúng, mà tôi nghĩ làm cho nhiều câu trả lời này trở nên kỳ quái mà không có bối cảnh ban đầu chính xác, đến mức một số bình luận dường như không có ý nghĩa. (Có lẽ cũng đánh cắp các điểm đại diện tiềm năng trong tương lai.) Tôi sẽ đề xuất rằng các câu hỏi với nền tảng chi tiết như vậy không bao giờ có thể là "bản sao chính xác". Sao cũng được ...
Peter Hansen

2
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

3
"Lưu ý rằng rất khó để chứng minh điều tiêu cực" - điều này được tin tưởng rộng rãi nhưng hoàn toàn sai và rõ ràng ... như chúng ta đã biết ít nhất kể từ khi Euclid chứng minh rằng không có nguyên tố lớn nhất. Và bất kỳ bằng chứng nào về P là bằng chứng về sự phủ định của (không phải P). Điều đúng là rất khó để chứng minh một phổ quát thực nghiệm, tích cực hoặc tiêu cực, ví dụ: "tất cả các con quạ đều màu đen" hoặc "không có con quạ nào là màu trắng". Các thuật toán là phân tích, không theo kinh nghiệm, vì vậy đây là một ứng dụng sai đặc biệt xấu của quy tắc không có thật. ví dụ: bằng chứng cho thấy mẫu 'a' không khớp với bất kỳ chuỗi nào bắt đầu bằng 'b' không "rất khó".
Jim Balter

Câu trả lời:


66

Điều này thực sự khá đơn giản, mặc dù nó phụ thuộc vào việc thực hiện / cờ *:

$a

Sẽ khớp với một ký tự asau khi kết thúc chuỗi. Chúc may mắn.

CẢNH BÁO:
Biểu thức này rất tốn kém - nó sẽ quét toàn bộ dòng, tìm neo cuối dòng và chỉ sau đó không tìm thấy avà trả về kết quả khớp âm. (Xem bình luận bên dưới để biết thêm chi tiết.)


* Ban đầu tôi không suy nghĩ nhiều về regrec đa chế độ, nơi $cũng khớp với cuối dòng. Trên thực tế, nó sẽ khớp với chuỗi trống ngay trước dòng mới , vì vậy một ký tự bình thường như akhông bao giờ có thể xuất hiện sau đó $.


50
Biểu thức này rất tốn kém - nó sẽ quét toàn bộ dòng, tìm neo cuối dòng và chỉ sau đó không tìm thấy "a" và trả về kết quả trùng khớp. Tôi thấy phải mất ~ 480ms để quét tệp dòng ~ 275k. Trò chuyện "a ^" mất khoảng thời gian tương tự, ngay cả khi nó có vẻ hiệu quả hơn. Mặt khác, một cái nhìn tiêu cực không cần phải quét bất cứ thứ gì: "(?! X) x" (bất cứ thứ gì không theo sau x cũng theo x, tức là không có gì) mất khoảng 30ms, hoặc ít hơn 7% thời gian. (Được đo bằng thời gian gnu và egrep.)
arantius

1
Trong Perl sẽ phù hợp với giá trị hiện tại của $a. Tương đương với Perl $(?:a)cũng rất chậm perl -Mre=debug -e'$_=a x 50; /$(?:a)/'.
Brad Gilbert

@arantius, vui lòng xem câu trả lời của tôi về thời gian , vì tôi đã tìm thấy điều ngược lại chính xác được đo bằng timeitpython3.
nivk

Không có gì đáng ngạc nhiên khi sáu năm và một phiên bản chính của Python có thể thay đổi mọi thứ.
arantius

1
Trong cú pháp POSIX BRE, $asẽ khớp với văn bản bằng chữ $a, bởi vì $không hợp lệ là một neo trong mẫu đó.
phils

76

Đòn bẩy negative lookahead:

>>> import re
>>> x=r'(?!x)x'
>>> r=re.compile(x)
>>> r.match('')
>>> r.match('x')
>>> r.match('y')

RE này là một mâu thuẫn trong điều khoản và do đó sẽ không bao giờ phù hợp với bất cứ điều gì.

LƯU Ý:
Trong Python, re.match () ngầm thêm một neo đầu chuỗi ( \A) vào đầu biểu thức chính quy. Neo này rất quan trọng đối với hiệu suất: không có nó, toàn bộ chuỗi sẽ được quét. Những người không sử dụng Python sẽ muốn thêm neo một cách rõ ràng:

\A(?!x)x

@ Chris, vâng - cũng có, (?=x)(?!x)và vân vân (concatenations của lookaheads mâu thuẫn, và tương tự cho lookbehinds), và nhiều người cũng làm việc cho các giá trị tùy ý của x(lookbehinds cần xs rằng chuỗi trận đấu của chiều dài cố định).
Alex Martelli

1
Xuất hiện để làm việc tốt. Nhưng những gì về chỉ (?!) Thay vào đó? Vì () sẽ luôn khớp, nên (?!) Sẽ được đảm bảo không bao giờ khớp?
Peter Hansen

2
@Peter, vâng, nếu Python chấp nhận cú pháp đó (và các bản phát hành gần đây xuất hiện), thì nó cũng sẽ tự mâu thuẫn. Một ý tưởng khác (không hoàn toàn thanh lịch, nhưng bạn càng có nhiều ý tưởng để tìm ra một ý tưởng hoạt động trên tất cả các công cụ RE quan tâm) r'a\bc':, tìm kiếm một ranh giới từ ngay lập tức được bao quanh bởi các chữ cái ở cả hai bên (biến thể: ký tự không phải từ cả hai mặt).
Alex Martelli

1
Thật thú vị, bản gốc của tôi với một nghĩa đen đơn giản mà tôi "biết" sẽ không xuất hiện trong đầu vào của tôi hóa ra là nhanh nhất, trong Python. Với chuỗi đầu vào 5 MB và sử dụng chuỗi này trong thao tác phụ (), (?! X) x mất 21% lâu hơn, (?! ()) Là 16% và ($ ^) dài hơn 6%. Có thể có ý nghĩa trong một số trường hợp, mặc dù không phải trong tôi.
Peter Hansen

2
Điều đó có thể khá chậm perl -Mre=debug -e'$_=x x 8; /(?!x)x/'. Bạn có thể làm cho nó nhanh hơn bằng cách neo nó ở đầu \A(?!x)xhoặc cuối (?!x)x\z. perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Brad Gilbert

43

Một trong số đó đã bị bỏ lỡ:

^\b$

Nó không thể khớp bởi vì chuỗi trống không chứa ranh giới từ. Đã thử nghiệm trong Python 2.5.


7
Đây là câu trả lời tốt nhất. Nó không sử dụng giao diện, không vi phạm trong một số triển khai regex, không sử dụng một ký tự cụ thể (ví dụ 'a') và thất bại trong tối đa 3 bước xử lý (theo regex101.com) mà không quét toàn bộ chuỗi đầu vào. Điều này cũng dễ hiểu trong nháy mắt.
CubicleSoft

1
Điều này thực sự thất bại trong Emacs trong một số điều kiện nhất định (nếu có một dòng trống ở đầu hoặc cuối bộ đệm), tuy nhiên nó \`\b\'hoạt động, thay thế cú pháp Emacs cho "bắt đầu / kết thúc văn bản" (trái ngược với "bắt đầu / kết thúc văn bản" của dòng ").
phils

35

nhìn xung quanh:

(?=a)b

Đối với người mới regex: Nhìn tích cực về phía trước (?=a)đảm bảo rằng ký tự tiếp theo là a, nhưng không thay đổi vị trí tìm kiếm (hoặc bao gồm 'a' trong chuỗi khớp). Bây giờ, ký tự tiếp theo được xác nhận là a, phần còn lại của regex ( b) chỉ khớp với nếu ký tự tiếp theo là b. Do đó, regex này chỉ khớp khi một nhân vật là cả hai abcùng một lúc.


30

a\bc, trong đó \bmột biểu thức có độ rộng bằng 0 khớp với ranh giới từ.

Nó không thể xuất hiện ở giữa một từ mà chúng ta buộc nó phải.


Nếu trường hợp sử dụng của bạn cho phép bạn neo mẫu vào đầu chuỗi, thì sự tăng cường đó sẽ ngăn công cụ regrec tìm kiếm và kiểm tra mọi phiên bản của một avăn bản.
phils

20

$.

.^

$.^

(?!)


1
Dễ thương! Tiềm thức của tôi đã đưa tôi ra khỏi những ý tưởng như ba ý tưởng đầu tiên, vì chúng là "bất hợp pháp" ... về mặt khái niệm, nhưng rõ ràng là không đến với regex. Tôi không nhận ra (!) Một ... sẽ phải tìm cái đó.
Peter Hansen

1
Được rồi, tôi thích câu trả lời (?!) ... hiệu quả những gì Alex đề xuất. Lưu ý rằng trong stackoverflow.com/questions/1723182 (được chỉ ra bởi Amarghosh ở trên), ai đó tuyên bố "một số hương vị" của regex sẽ coi đó là lỗi cú pháp. Python thích nó mặc dù tốt. Lưu ý rằng tất cả các đề xuất khác của bạn đều thất bại với các chế độ re.DOTALL | re.MULTILINE trong Python.
Peter Hansen

1
Điều này đã được thử nghiệm? Tôi đã giả định rằng ^chỉ có ý nghĩa đặc biệt là ký tự đầu tiên của biểu thức chính quy, và $chỉ có ý nghĩa đặc biệt ở phần cuối của biểu thức chính quy, trừ khi biểu thức chính quy là biểu thức nhiều dòng.
PP.

Trên thực tế trong Perl /$./có nghĩa là một cái gì đó hoàn toàn khác nhau. Nó có nghĩa phù hợp với giá trị hiện tại của $.(số dòng đầu vào) . Thậm chí /$(.)/có thể phù hợp với một cái gì đó nếu bạn viết use re '/s';trước nó. ( perl -E'say "\n" =~ /$(.)/s || 0')
Brad Gilbert

Trong cú pháp POSIX BRE, ^$chỉ đặc biệt ở phần đầu và kết thúc (tương ứng) của mô hình, vì vậy không ai trong số $.hoặc .^hoặc $.^sẽ làm việc. (?!)là một tính năng Perl / PCRE, tôi tin.
phils

13

Kết hợp tối đa

a++a

Ít nhất một cái atheo sau bởi bất kỳ số lượng nào a, mà không cần quay lại. Sau đó cố gắng để phù hợp với một hơn nữa a.

hoặc biểu thức phụ độc lập

Điều này tương đương với việc đưa a+vào một biểu thức phụ độc lập, theo sau là một biểu thức khác a.

(?>a+)a

10

Perl 5.10 hỗ trợ các từ điều khiển đặc biệt gọi là "động từ", được bao trong (*...)chuỗi. (So ​​sánh với (?...)chuỗi đặc biệt.) Trong số đó, nó bao gồm (*FAIL)động từ trả về từ biểu thức chính quy ngay lập tức.

Lưu ý rằng các động từ cũng được triển khai trong PCRE ngay sau đó, vì vậy bạn cũng có thể sử dụng chúng trong PHP hoặc các ngôn ngữ khác bằng thư viện PCRE. (Tuy nhiên, bạn không thể sử dụng Python hoặc Ruby. Họ sử dụng công cụ riêng của họ.)


Các tài liệu cho điều đó tại perldoc.perl.org/perlre.html#%28%2AFAIL%29-%28%2AF%29 nói "Mẫu này không khớp với gì và luôn thất bại. Nó tương đương với (?!), Nhưng dễ dàng hơn đọc. Thực tế, (?!) được tối ưu hóa thành (* FAIL) trong nội bộ. " Thật thú vị, vì (?!) Là câu trả lời "thuần túy" yêu thích của tôi cho đến nay (mặc dù nó không hoạt động trong Javascript). Cảm ơn.
Peter Hansen

10
\B\b

\bkhớp với các ranh giới từ - vị trí giữa một chữ cái không phải là chữ cái (hoặc ranh giới chuỗi).
\Blà phần bổ sung của nó - nó khớp với vị trí giữa hai chữ cái hoặc giữa các chữ cái không.

Họ không thể phù hợp với bất kỳ vị trí nào.

Xem thêm:


Đây có vẻ như là một giải pháp tuyệt vời, miễn là nó được neo vào một điểm cụ thể (phần đầu của văn bản có vẻ hợp lý). Nếu bạn không làm điều đó thì đó là một giải pháp tồi tệ , bởi vì mọi ranh giới không từ trong văn bản sẽ được kiểm tra để xem liệu nó có được theo sau bởi một ranh giới từ không! Vì vậy, phiên bản hợp lý sẽ là một cái gì đó như ^\B\b. Trong các ngôn ngữ nơi "bắt đầu văn bản" và "bắt đầu dòng" có cú pháp khác nhau, bạn sẽ muốn sử dụng cú pháp "bắt đầu văn bản", nếu không, bạn sẽ kiểm tra từng dòng. (ví dụ: trong Emacs, điều này sẽ là \`\B\bhoặc "\\`\\B\\b".)
phils

Điều đó nói rằng, bây giờ tôi đã lưu ý rằng mục đích đã nêu của câu hỏi này là để có được một biểu thức chính quy để sử dụng trong một nhóm, trong trường hợp đó ^là vấn đề trong cú pháp regrec nhất định (ví dụ POSIX BRE) khi ^chỉ là ký tự đầu tiên khi nó là ký tự đầu tiên của mẫu, và mặt khác phù hợp với một ^nhân vật theo nghĩa đen .
phils

@phils - Tôi nghĩ rằng bạn đang xem xét nó :)- đây là một câu hỏi không thực tế, trong đó mục tiêu là tìm một câu trả lời thú vị - không phải là một câu trả lời hiệu quả. Điều đó nói rằng, mẫu có thể bị từ chối trong thời gian lót (với kích thước của chuỗi mục tiêu), vì vậy nó không tệ cho regex - hầu hết mẫu ở đây đều giống nhau và thậm chí ^có thể là tuyến tính nếu không được tối ưu hóa.
Kobi

Re: tối ưu hóa, tôi sẵn sàng bỏ qua một công cụ regrec hy vọng tìm thấy "phần đầu của văn bản" ở bất kỳ vị trí nào khác :)
phils

Ngoài ra, đây không phải là một câu hỏi và trả lời không thực tế - lý do duy nhất tôi kết thúc ở đây là để xem liệu có ai có thể đề xuất một giải pháp hiệu quả hơn cho riêng tôi cho mục đích thực tế là định cấu hình một biến Emac cụ thể yêu cầu giá trị regrec không, nhưng tôi muốn vô hiệu hóa hiệu quả.
phils

8

Điều này dường như làm việc:

$.

2
Điều đó tương tự như ví dụ của Ferdinand.
Gumbo

9
Và nó sẽ khớp trong chế độ dot-Match-newlines.
Tim Pietzcker

Trong Perl sẽ thực sự khớp với số dòng đầu vào hiện tại $.. Trong trường hợp đó bạn phải dùng đến $(.)hoặc tương đương hơn $(?:.).
Brad Gilbert

Trong cú pháp POSIX BRE, $.sẽ khớp với một chữ $theo sau bởi bất kỳ ký tự nào, bởi vì $không hợp lệ là một neo trong mẫu đó.
phils

8

Làm thế nào về $^hoặc có thể (?!)


3
Một ngắt dòng sẽ được khớp với biểu thức này trong chế độ ^khớp với điểm bắt đầu và $điểm cuối của dòng.
Gumbo

4
Có lẽ ý anh là (?!)- một cái nhìn tiêu cực cho một chuỗi trống. Nhưng một số hương vị regex cũng sẽ coi đó là lỗi cú pháp.
Alan Moore

1
Một chuỗi rỗng khớp với chuỗi đầu tiên, ít nhất là trong JavaScript.
Roland Pihlakas

Trong cú pháp POSIX BRE, $^sẽ khớp với các ký tự bằng chữ đó, bởi vì các ký tự không hợp lệ là các ký tự liên kết (nghĩa là lý do bạn sử dụng mẫu này khiến nó không thực hiện được những gì bạn muốn.)
phils

5

Nhanh nhất sẽ là:

r = re.compile(r'a^')
r.match('whatever')

'a' có thể là bất kỳ ký tự không đặc biệt nào ('x', 'y'). Việc triển khai của Knio có thể thuần túy hơn một chút nhưng chuỗi này sẽ nhanh hơn cho tất cả các chuỗi không bắt đầu với bất kỳ ký tự nào bạn chọn thay vì 'a' vì nó sẽ không khớp với ký tự đầu tiên thay vì sau ký tự thứ hai trong các trường hợp đó.


Thật vậy, (. ^) Sẽ chậm hơn khoảng 10% so với (\ x00 ^) trong trường hợp của tôi.
Peter Hansen

1
Tôi chấp nhận điều này, vì sử dụng bất kỳ giá trị nào ngoài \ n vì ký tự được đảm bảo không bao giờ khớp và tôi thấy nó dễ đọc hơn một chút (với điều kiện tương đối ít người là chuyên gia regex) so với tùy chọn (?! X) x , mặc dù tôi đã bình chọn rằng một trong những quá. Trong trường hợp của tôi, đối với một trong hai tùy chọn, tôi sẽ cần một nhận xét để giải thích nó, vì vậy tôi nghĩ rằng tôi sẽ chỉ điều chỉnh nỗ lực ban đầu của mình thành '\ x00NEVERMATCHES ^'. Tôi nhận được sự đảm bảo không trùng khớp của câu trả lời này, với tài liệu tự ghi chép ban đầu của tôi. Cảm ơn tất cả các câu trả lời!
Peter Hansen

3
Điều này thực sự hoạt động và nếu vậy, ai quyết định phá vỡ với Unix? Trong regexps Unix, ^chỉ đặc biệt là ký tự đầu tiên và tương tự như vậy $. Với bất kỳ công cụ Unix nào, biểu thức chính quy đó sẽ khớp với bất kỳ thứ gì có chứa chuỗi ký tự a^.
JaakkoK

Heh, đó là một cuộc tấn công tốt. Tôi chưa bao giờ thử nghiệm chống lại chuỗi chữ đó.
Adam Nelson

Ồ, nếu điều đó phá vỡ regexps Unix, thì bạn sẽ thích >^.
CubicleSoft

4

Python sẽ không chấp nhận nó, nhưng Perl sẽ:

perl -ne 'print if /(w\1w)/'

Regex này (về mặt lý thuyết) nên cố gắng khớp số lượng ws (chẵn) vô hạn , bởi vì nhóm đầu tiên ( ()s) đệ quy vào chính nó. Perl dường như không đưa ra bất kỳ cảnh báo nào, ngay cả dưới use strict; use warnings;, vì vậy tôi cho rằng ít nhất là hợp lệ và thử nghiệm (tối thiểu) của tôi không khớp với bất cứ điều gì, vì vậy tôi gửi nó cho bài phê bình của bạn.


1
Lý thuyết luôn luôn tốt đẹp, nhưng trong thực tế tôi nghĩ rằng tôi lo lắng về các biểu thức thông thường có mô tả bao gồm từ "vô hạn"!
Peter Hansen

perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
Brad Gilbert

@BradGilbert - Chạy nó ở đây (5.10, một chút lỗi thời) tạo ra "regex fail", như OP yêu cầu. Có phù hợp với hệ thống của bạn?
Chris Lutz

4

[^\d\D]hoặc (?=a)bhoặc a$ahoặca^a


Cảm ơn. Lưu ý rằng (?! X) x là câu trả lời đầu tiên được đưa ra, được liệt kê ở trên.
Peter Hansen

Vâng, có vẻ như tôi đã quét những người trả lời khác quá nhanh.
Bart Kiers

4

Điều này sẽ không hoạt động với Python và nhiều ngôn ngữ khác, nhưng trong regex Javascript, []là một lớp ký tự hợp lệ không thể phù hợp. Vì vậy, những điều sau đây sẽ thất bại ngay lập tức, bất kể đầu vào là gì:

var noMatch = /^[]/;

Tôi thích nó hơn là /$a/với tôi, nó truyền đạt rõ ràng ý định của nó. Và như khi bạn cần nó, tôi cần nó bởi vì tôi cần một dự phòng cho một mẫu được biên dịch động dựa trên đầu vào của người dùng. Khi mẫu không hợp lệ, tôi cần thay thế nó bằng một mẫu không khớp. Đơn giản hóa, nó trông như thế này:

try {
    var matchPattern = new RegExp(someUserInput);
}
catch (e) {
    matchPattern = noMatch;
}

4

Tất cả các ví dụ liên quan đến một công cụ đối sánh ranh giới theo cùng một công thức. Công thức:

  1. Lấy bất kỳ công cụ đối sánh ranh giới nào: ^, $, \ b, \ A, \ Z, \ z

  2. Làm ngược lại với ý nghĩa của chúng

Ví dụ:

^ và \ A có nghĩa là bắt đầu, vì vậy đừng sử dụng chúng vào đầu

^ --> .^
\A --> .\A

\ b khớp với một ranh giới từ để sử dụng nó ở giữa

\b --> .\b.

$, \ Z và \ z có nghĩa là cuối cùng, vì vậy cuối cùng đừng sử dụng chúng

$ --> $.
\Z --> \Z.
\z --> \z.

Những người khác liên quan đến việc sử dụng lookahead và lookbehind cũng hoạt động với cùng một sự tương tự: Nếu bạn đưa ra cái nhìn tích cực hoặc tiêu cực theo sau là một cái gì đó ngược lại

(?=x)[^x]
(?!x)x

Nếu bạn cho cái nhìn tích cực hoặc tiêu cực theo sau một cái gì đó ngược lại

[^x](?<=x)
x(?<!x)

Họ có thể là nhiều mô hình như vậy và nhiều tương tự như vậy.


3

Rất nhiều câu trả lời hay!

Tương tự như câu trả lời của @ nivk, tôi muốn chia sẻ so sánh hiệu suất cho Perl cho các biến thể khác nhau của regex không bao giờ khớp.

  1. Đầu vào: chuỗi ascii giả ngẫu nhiên (25.000 dòng khác nhau, dài 8-16):

Tốc độ Regex:

Total for   \A(?!x)x: 69.675450 s, 1435225 lines/s
Total for       a\bc: 71.164469 s, 1405195 lines/s
Total for    (?>a+)a: 71.218324 s, 1404133 lines/s
Total for       a++a: 71.331362 s, 1401907 lines/s
Total for         $a: 72.567302 s, 1378031 lines/s
Total for     (?=a)b: 72.842308 s, 1372828 lines/s
Total for     (?!x)x: 72.948911 s, 1370822 lines/s
Total for       ^\b$: 79.417197 s, 1259173 lines/s
Total for         $.: 88.727839 s, 1127041 lines/s
Total for       (?!): 111.272815 s, 898692 lines/s
Total for         .^: 115.298849 s, 867311 lines/s
Total for    (*FAIL): 350.409864 s, 285380 lines/s
  1. Đầu vào: / usr / share / dict / words (100.000 từ tiếng Anh).

Tốc độ Regex:

Total for   \A(?!x)x: 128.336729 s, 1564805 lines/s
Total for     (?!x)x: 132.138544 s, 1519783 lines/s
Total for       a++a: 133.144501 s, 1508301 lines/s
Total for    (?>a+)a: 133.394062 s, 1505479 lines/s
Total for       a\bc: 134.643127 s, 1491513 lines/s
Total for     (?=a)b: 137.877110 s, 1456528 lines/s
Total for         $a: 152.215523 s, 1319326 lines/s
Total for       ^\b$: 153.727954 s, 1306346 lines/s
Total for         $.: 170.780654 s, 1175906 lines/s
Total for       (?!): 209.800379 s, 957205 lines/s
Total for         .^: 217.943800 s, 921439 lines/s
Total for    (*FAIL): 661.598302 s, 303540 lines/s

(Ubuntu trên Intel i5-3320M, nhân Linux 4.13, Perl 5.26)


Dưới đây là so sánh JavaScript của một số phương pháp được đề cập ở đây: jsperf.com/regex-that-never-matches
thdoan

2

Tôi tin rằng

\Z RE FAILS! \A

bao gồm cả các trường hợp trong đó biểu thức chính quy bao gồm các cờ như MULTILINE, DOTALL, v.v.

>>> import re
>>> x=re.compile(r"\Z RE FAILS! \A")
>>> x.match('')
>>> x.match(' RE FAILS! ')
>>>

Tôi tin rằng (nhưng tôi đã không điểm chuẩn) rằng bất kể độ dài (> 0) của chuỗi giữa \Z\A, thời gian đến thất bại là không đổi.


2
(*FAIL)

hoặc là

(*F)

Với PCRE và PERL, bạn có thể sử dụng động từ điều khiển quay lui này để buộc mẫu bị lỗi ngay lập tức.


2

Sau khi thấy một số câu trả lời tuyệt vời này, nhận xét của @ arantius (liên quan đến thời gian $xso x^với (?!x)x) về câu trả lời hiện được chấp nhận khiến tôi muốn đặt thời gian cho một số giải pháp được đưa ra cho đến nay.

Sử dụng tiêu chuẩn dòng 275k của @ arantius, tôi đã chạy các thử nghiệm sau trong Python (v3.5.2, IPython 6.2.1).

TL; DR: 'x^''x\by'nhanh nhất theo hệ số ít nhất ~ 16, và trái với phát hiện của @ arantius, (?!x)xlà một trong những tốc độ chậm nhất (chậm hơn ~ 37 lần). Vì vậy, câu hỏi tốc độ chắc chắn là phụ thuộc thực hiện. Tự kiểm tra nó trên hệ thống dự định của bạn trước khi cam kết nếu tốc độ là quan trọng đối với bạn.

CẬP NHẬT: Rõ ràng có sự khác biệt lớn giữa thời gian 'x^''a^'. Vui lòng xem câu hỏi này để biết thêm thông tin và chỉnh sửa trước đó cho thời gian chậm hơn athay vì x.

In [1]: import re

In [2]: with open('/tmp/longfile.txt') as f:
   ...:     longfile = f.read()
   ...:     

In [3]: len(re.findall('\n',longfile))
Out[3]: 275000

In [4]: len(longfile)
Out[4]: 24733175

In [5]: for regex in ('x^','.^','$x','$.','$x^','$.^','$^','(?!x)x','(?!)','(?=x)y','(?=x)(?!x)',r'x\by',r'x\bx',r'^\b$'
    ...: ,r'\B\b',r'\ZNEVERMATCH\A',r'\Z\A'):
    ...:     print('-'*72)
    ...:     print(regex)
    ...:     %timeit re.search(regex,longfile)
    ...:     
------------------------------------------------------------------------
x^
6.98 ms ± 58.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
.^
155 ms ± 960 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x
111 ms ± 2.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.
111 ms ± 1.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x^
112 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.^
113 ms ± 1.44 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$^
111 ms ± 839 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?!x)x
257 ms ± 5.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?!)
203 ms ± 1.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?=x)y
204 ms ± 4.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?=x)(?!x)
210 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
x\by
7.41 ms ± 122 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
x\bx
7.42 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
^\b$
108 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\B\b
387 ms ± 5.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
\ZNEVERMATCH\A
112 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\Z\A
112 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Lần đầu tiên tôi chạy cái này, tôi đã quên mất r3 biểu thức cuối cùng, vì vậy '\b'được hiểu là '\x08', ký tự backspace. Tuy nhiên, thật ngạc nhiên, tôi 'a\x08c'đã nhanh hơn kết quả nhanh nhất trước đó! Công bằng mà nói, nó vẫn sẽ phù hợp với văn bản đó, nhưng tôi nghĩ nó vẫn đáng chú ý vì tôi không chắc tại sao nó nhanh hơn.

In [6]: for regex in ('x\by','x\bx','^\b$','\B\b'):
    ...:     print('-'*72)
    ...:     print(regex, repr(regex))
    ...:     %timeit re.search(regex,longfile)
    ...:     print(re.search(regex,longfile))
    ...:     
------------------------------------------------------------------------
y 'x\x08y'
5.32 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
x 'x\x08x'
5.34 ms ± 66.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
$ '^\x08$'
122 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
None
------------------------------------------------------------------------
\ '\\B\x08'
300 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
None

Tệp thử nghiệm của tôi đã được tạo bằng công thức cho "... Nội dung có thể đọc và không có dòng trùng lặp" (trên Ubuntu 16.04):

$ ruby -e 'a=STDIN.readlines;275000.times do;b=[];rand(20).times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > /tmp/longfile.txt

$ head -n5 /tmp/longfile.txt 
unavailable speedometer's garbling Zambia subcontracted fullbacks Belmont mantra's
pizzicatos carotids bitch Hernandez renovate leopard Knuth coarsen
Ramada flu occupies drippings peaces siroccos Bartók upside twiggier configurable perpetuates tapering pint paralyzed
vibraphone stoppered weirdest dispute clergy's getup perusal fork
nighties resurgence chafe

\B\blà thiếu sót về mặt hiệu suất một cách khủng khiếp (như mọi mẫu không được neo vào một vị trí, nhưng mẫu này đặc biệt xấu). ^\B\bThay vào đó hãy thử điểm chuẩn .
phils

2

Regex trống

Regex tốt nhất để không bao giờ phù hợp với bất cứ điều gì là một regex trống. Nhưng tôi không chắc chắn tất cả các công cụ regex sẽ chấp nhận điều đó.

Regex không thể

Giải pháp khác là tạo ra một regex không thể. Tôi thấy rằng $-^chỉ cần hai bước để tính toán bất kể kích thước văn bản của bạn ( https://regex101.com/r/yjcs1Z/1 ).

Để tham khảo:

  • $^$.thực hiện 36 bước để tính toán -> O (1)
  • \b\B thực hiện 1507 bước trên mẫu của tôi và tăng theo số lượng ký tự trong chuỗi của bạn -> O (n)

Chủ đề phổ biến hơn về câu hỏi này:


1

Có lẽ điều này?

/$.+^/

Trong Python, cách tiếp cận này chỉ hoạt động nếu bạn điều khiển các cờ : re.compile('$.+^', re.MULTILINE|re.DOTALL).search('a\nb\nc\n')trả về một đối tượng khớp tương ứng với b và c (và tất cả các dòng mới liền kề và ở giữa). Cách tiếp cận nhìn tiêu cực mà tôi khuyên bạn nên làm việc (nghĩa là không khớp với bất cứ thứ gì) cho bất kỳ tổ hợp cờ nào mà nó có thể được biên dịch.
Alex Martelli

Xấu của tôi - trộn lẫn $^.
Chris Lutz

1
Đây có thể là một nỗ lực tìm kiếm kết thúc chuỗi trước khi bắt đầu, nhưng tôi đã thấy rằng $ không có nghĩa là 'kết thúc chuỗi' trừ khi đó là ký tự cuối cùng của biểu thức chính quy và tôi mong đợi một hành vi tương tự được áp dụng đến ^, do đó, chuỗi này có thể khớp với một chuỗi con bắt đầu bằng $ theo nghĩa đen và kết thúc bằng một chữ ^
pavium

@pavium, nó chắc chắn không hoạt động theo cách đó trong Python hoặc Javascript. Trừ khi bạn thoát chúng bằng \ hoặc đưa chúng vào một bộ ký tự có [], các ký tự đặc biệt như $ và ^ không được coi là chữ. Trong ngôn ngữ nào bạn đã quan sát điều này?
Peter Hansen

Trong Perl, ít nhất, điều đó nên được viết /\z.+\A/(xem perldoc perlre ) Điều đó ngăn chế độ đa dòng và một dòng ( use re '/ms') ảnh hưởng đến nó.
Brad Gilbert

0
'[^0-9a-zA-Z...]*'

và thay thế ... bằng tất cả các ký hiệu có thể in được;). Đó là cho một tập tin văn bản.


Tôi nghĩ rằng phải có một cách ngắn hơn cho điều đó, nhưng đó cũng là suy nghĩ đầu tiên của tôi ^^
FP

4
Điều này sẽ phù hợp với chuỗi trống. Để bắt mọi ký tự có thể, hãy sử dụng [^\x00-\xFF]+(đối với các triển khai dựa trên byte).
Ferdinand Beyer

6
Một biểu hiện tốt hơn sẽ là [^\s\S]. Nhưng như Ferdinand Beyer đã nói, nó sẽ khớp với một chuỗi rỗng.
Gumbo

3
Regex của Drakosha có thể khớp với một chuỗi rỗng vì *; bỏ nó đi, hoặc thay thế nó bằng +, và nó phải khớp với ít nhất một ký tự. Nếu lớp loại trừ tất cả các ký tự có thể, nó không thể khớp với bất cứ thứ gì.
Alan Moore

0

Điều gì về thay vì regex, chỉ sử dụng một câu lệnh if luôn sai? Trong javascript:

var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}

Tôi đã thêm một bình luận để trả lời câu hỏi của Charlie, giải thích lý do tại sao cách tiếp cận này không được mong muốn. Nói tóm lại, tôi cần một nhóm trong regex sẽ luôn được sử dụng, nhưng trong một số trường hợp, nhóm phải được xây dựng để đảm bảo nó không bao giờ có thể khớp.
Peter Hansen

-2

Một giải pháp di động sẽ không phụ thuộc vào việc triển khai regrec là chỉ sử dụng một chuỗi không đổi mà bạn chắc chắn sẽ không bao giờ xuất hiện trong các thông điệp tường trình. Ví dụ, tạo một chuỗi dựa trên các điều sau đây:

cat /dev/urandom | hexdump | head -20
0000000 5d5d 3607 40d8 d7ab ce72 aae1 4eb3 ae47
0000010 c5e2 b9e8 910d a2d9 2eb3 fdff 6301 c85f
0000020 35d4 c282 e439 33d8 1c73 ca78 1e4d a569
0000030 8aca eb3c cbe4 aff7 d079 ca38 8831 15a5
0000040 818b 323f 0b02 caec f17f 387b 3995 88da
0000050 7b02 c80b 2d42 8087 9758 f56f b71f 0053
0000060 1501 35c9 0965 2c6e 03fe 7c6d f0ca e547
0000070 aba0 d5b6 c1d9 9bb2 fcd1 5ec7 ee9d 9963
0000080 6f0a 2c91 39c2 3587 c060 faa7 4ea4 1efd
0000090 6738 1a4c 3037 ed28 f62f 20fa 3d57 3cc0
00000a0 34f0 4bc2 3067 a1f7 9a87 086b 2876 1072
00000b0 d9e1 6b8f 5432 a60e f0f5 00b5 d9ef ed6f
00000c0 4a85 70ee 5ec4 a378 7786 927f f126 2ec2
00000d0 18c5 46fe b167 1ae6 c87c 1497 48c9 3c09
00000e0 8d09 e945 13ce 7da2 08af 1a96 c24c c022
00000f0 b051 98b3 2bf5 4d7d 5ec4 e016 a50d 355b
0000100 0e89 d9dd b153 9f0e 9a42 a51f 2d46 2435
0000110 ef35 17c2 d2aa 3cc7 e2c3 e711 d229 f108
0000120 324e 5d6a 650a d151 bc55 963f 41d3 66ee
0000130 1d8c 1fb1 1137 29b2 abf7 3af7 51fe 3cf4

Chắc chắn, đây không phải là một thách thức trí tuệ, mà giống như lập trình băng keo .


-6
new Regex(Guid.NewGuid().ToString())

Tạo một mẫu chỉ chứa các chữ số và ' -' (không có ký tự regex nào đặc biệt) nhưng không thể thống kê cho cùng một chuỗi xuất hiện ở bất cứ đâu trước đó (vì đó là toàn bộ điểm của GUID.)


2
"Không thể thống kê"? Huh? Tùy thuộc vào cách tính GUID, có thể và thường khá đơn giản để dự đoán các GUID tiếp theo (vì chúng phụ thuộc vào máy tính chúng và thời gian). Bạn có nghĩa là "không thể", "với xác suất rất nhỏ", nhưng bạn không thể nói "không thể" ngay cả đối với các chuỗi hoàn toàn ngẫu nhiên. Regex của bạn sẽ khớp với số lượng chuỗi vô hạn - câu hỏi này đang tìm kiếm một chuỗi không khớp với bất cứ điều gì. Không bao giờ.
Ferdinand Beyer
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.