Regex - làm thế nào để khớp mọi thứ trừ một mẫu cụ thể


171

Làm cách nào để tôi viết regex để khớp với bất kỳ chuỗi nào không đáp ứng một mẫu cụ thể? Tôi đang phải đối mặt với một tình huống mà tôi phải khớp một mẫu (A và ~ B).


PCRE sẽ là tốt nhất cho điều này: xem Mô hình Regex để khớp, Không bao gồm khi Lôi / Ngoại trừ giữa . Tôi đã xóa findstrthẻ vì tất cả các câu trả lời ở đây không hợp lệ cho thẻ.
Wiktor Stribiżew

Câu trả lời:


192

Bạn có thể sử dụng một xác nhận nhìn về phía trước:

(?!999)\d{3}

Ví dụ này phù hợp với ba chữ số khác 999.


Nhưng nếu bạn không thực hiện biểu thức chính quy với tính năng này (xem So sánh các hương vị biểu thức chính quy ), bạn có thể phải tự xây dựng một biểu thức chính quy với các tính năng cơ bản.

Một biểu thức chính quy tương thích chỉ với cú pháp cơ bản sẽ là:

[0-8]\d\d|\d[0-8]\d|\d\d[0-8]

Điều này cũng không phù hợp với bất kỳ chuỗi ba chữ số không 999.


1
Nhìn về phía trước không phải là cú pháp biểu thức chính quy tiêu chuẩn, nó là một phần mở rộng Perl, nó sẽ chỉ hoạt động trong Perl, PCRE (Perl-Tương thích RegEx) hoặc các triển khai không chuẩn khác
Juliano

10
Nó có thể không chuẩn, nhưng hầu hết các ngôn ngữ hiện đại không hỗ trợ nó? Ngôn ngữ nào không hỗ trợ giao diện trong những ngày này?
Bryan Oakley

1
Đúng. Nhưng hầu hết các hương vị regex đều hỗ trợ tính năng này (xem < normal-expressions.info/refflavors.html> ).
Gumbo

1
tôi nghĩ rằng regex cuối cùng cũng sẽ không khớp với 009, 019 ... vv
Sebastian Viereck

1
Tiêu chuẩn Lex cho C không sử dụng PCRE :-(
pieman72

30

Nếu bạn muốn ghép một từ A trong một chuỗi và không khớp với một từ B. Ví dụ: Nếu bạn có một văn bản:

1. I have a two pets - dog and a cat
2. I have a pet - dog

Nếu bạn muốn tìm kiếm các dòng văn bản CÓ chó cho thú cưng và KHÔNG CÓ mèo, bạn có thể sử dụng biểu thức thông thường này:

^(?=.*?\bdog\b)((?!cat).)*$

Nó sẽ chỉ tìm thấy dòng thứ hai:

2. I have a pet - dog

Ông đã không đề cập đến nó trong câu hỏi, nhưng OP thực sự đang sử dụng findstrlệnh DOS . Nó chỉ có một tập hợp nhỏ các khả năng mà bạn mong muốn tìm thấy trong một công cụ regex; lookahead không nằm trong số đó. (Tôi vừa tự thêm thẻ findstr .)
Alan Moore

2
hm, vâng, bây giờ tôi đã tìm thấy một trong những bình luận của anh ấy về bài viết. Tôi thấy Regex trong tiêu đề. Dù sao, nếu ai đó tìm thấy bài đăng này khi tìm kiếm cùng một biểu thức thông thường, như tôi đã làm, có lẽ nó có thể hữu ích cho ai đó :) cảm ơn vì đã bình luận
Aleks

15

Khớp với mẫu và sử dụng ngôn ngữ máy chủ để đảo ngược kết quả boolean của trận đấu. Điều này sẽ dễ đọc và dễ bảo trì hơn nhiều.


1
Sau đó, tôi chỉ kết thúc bằng (~ A hoặc B) thay vì (A và ~ B). Nó không giải quyết vấn đề của tôi.
chú ý

1
Mã giả: Chuỗi toTest; if (toTest.matches (A) VÀ! toTest.matches (B)) {...}
Ben S

Tôi nên rõ ràng hơn - các mảnh không hoàn toàn độc lập. Nếu A khớp với một phần của chuỗi, thì chúng tôi quan tâm nếu ~ B khớp với phần còn lại của chuỗi (nhưng không nhất thiết là toàn bộ). Điều này là cho chức năng findstr dòng lệnh windows, mà tôi tìm thấy bị giới hạn ở các regex thực sự, vì vậy điểm moot.
chú ý

8

Lưu ý, làm sống lại câu hỏi cổ xưa này bởi vì nó có một giải pháp đơn giản không được đề cập. (Tìm thấy câu hỏi của bạn trong khi thực hiện một số nghiên cứu cho nhiệm vụ tiền thưởng regex .)

Tôi đang phải đối mặt với một tình huống mà tôi phải khớp một mẫu (A và ~ B).

Regex cơ bản cho điều này là đơn giản đáng sợ: B|(A)

Bạn chỉ cần bỏ qua các trận đấu tổng thể và kiểm tra các ảnh chụp nhóm 1, sẽ chứa A.

Một ví dụ (với tất cả các từ chối trách nhiệm về phân tích cú pháp html trong regex): A là chữ số, B là chữ số trong <a tag

Các regex: <a.*?<\/a>|(\d+)

Bản trình diễn (nhìn vào Nhóm 1 ở khung bên phải phía dưới)

Tài liệu tham khảo

Làm thế nào để khớp mẫu ngoại trừ trong các tình huống s1, s2, s3

Làm thế nào để khớp với một mẫu trừ khi ...


Điều này nghe có vẻ quá tốt là đúng! Thật không may, giải pháp này không phổ biến và nó thất bại trong Emacs, ngay cả sau khi thay thế \dbằng [[:digit:]]. Tham chiếu đầu tiên đề cập đến nó dành riêng cho Perl và PHP: "Có một biến thể sử dụng cú pháp cụ thể cho Perl và PHP thực hiện giống nhau."
Miguelmorin

4

Phần bổ sung của ngôn ngữ thông thường cũng là ngôn ngữ thông thường, nhưng để xây dựng ngôn ngữ đó, bạn phải xây dựng DFA cho ngôn ngữ thông thường và làm cho bất kỳ thay đổi trạng thái hợp lệ nào thành lỗi. Xem điều này cho một ví dụ. Những gì trang không nói là nó được chuyển đổi /(ac|bd)/thành /(a[^c]?|b[^d]?|[^ab])/. Việc chuyển đổi từ DFA trở lại biểu thức chính quy không phải là chuyện nhỏ. Sẽ dễ dàng hơn nếu bạn có thể sử dụng biểu thức chính quy không thay đổi và thay đổi ngữ nghĩa trong mã, như được đề xuất trước đây.


2
Nếu tôi đang làm việc với regex thực tế thì tất cả sẽ là tranh luận. Regex bây giờ dường như đề cập đến không gian CSG-ish (?) Vô nghĩa của khớp mẫu mà hầu hết các langauges hỗ trợ. Vì tôi cần khớp (A và ~ B), không có cách nào để loại bỏ phủ định và vẫn thực hiện tất cả trong một bước.
chú ý

Lookahead, như được mô tả ở trên, sẽ làm điều đó nếu findstr làm bất cứ điều gì ngoài các biểu thức DFA thực sự. Toàn bộ điều này thật kỳ quặc và tôi không biết tại sao tôi phải thực hiện kiểu dòng lệnh này (đợt ngay bây giờ). Đó chỉ là một ví dụ khác về việc tay tôi bị trói.
chú ý

1
@notnot: Bạn đang sử dụng findstr từ Windows? Sau đó, bạn chỉ cần / v. Giống như: findstr Một inputfile | findstr / v B> outputfile.txt Cái đầu tiên khớp với tất cả các dòng với A, cái thứ hai khớp với tất cả các dòng không có B.
Juliano

Cảm ơn! Đó thực sự chính xác là những gì tôi cần. Mặc dù vậy, tôi đã không hỏi câu hỏi theo cách đó, vì vậy tôi vẫn đưa ra câu trả lời cho Gumbo để có câu trả lời khái quát hơn.
chú ý

1

mô hình - tái

str.split(/re/g) 

sẽ trả lại mọi thứ trừ mẫu.

Kiểm tra tại đây


Bạn có thể muốn đề cập rằng bạn cần tham gia sau đó một lần nữa.
tomdemuyt

Một cách tiếp cận tương tự đang sử dụng replace str.replace(/re/g, ''), sau đó không cần phải tham gia lại với họ. Ngoài ra nếu bạn ném vào một dấu vết tốt đẹp? như str.replace(/\re\s?/g, '')sau đó bạn thoát khỏi bất kỳ không gian trùng lặp nào bạn sẽ có từ một thứ được thay thế ở giữa một chuỗi
jakecraige

0

Câu trả lời của tôi ở đây cũng có thể giải quyết vấn đề của bạn:

https://stackoverflow.com/a/27967674/543814

  • Thay vì Thay thế, bạn sẽ sử dụng Match.
  • Thay vì nhóm $1, bạn sẽ đọc nhóm $2.
  • Nhóm $2đã được thực hiện không bắt ở đó, mà bạn sẽ tránh.

Thí dụ:

Regex.Match("50% of 50% is 25%", "(\d+\%)|(.+?)");

Nhóm chụp đầu tiên chỉ định mẫu mà bạn muốn tránh. Nhóm bắt cuối cùng nắm bắt mọi thứ khác. Đơn giản chỉ cần đọc ra nhóm đó , $2.


0
(B)|(A)

sau đó sử dụng những gì nhóm 2 chụp ...


Anh ta cần phải nắm bắt không B, anh ta nhắm không chỉ là bỏ qua tất cả các mẫu B.
lục giác
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.