Biểu thức chính quy: Có toán tử AND không?


708

Rõ ràng, bạn có thể sử dụng |(ống?) Để đại diện OR, nhưng có cách nào để đại diện ANDkhông?

Cụ thể, tôi muốn khớp các đoạn văn bản có chứa TẤT CẢ một cụm từ nhất định, nhưng không theo thứ tự cụ thể.


1
Bạn có nghĩa là bạn muốn tìm cụm từ trong một văn bản, trong đó mỗi cụm từ đó là một hoán vị hợp lệ của các từ trong một cụm từ nhất định?
Nietzche-jou

2
Tôi đang đặt nó ở đây vì ba hoặc bốn câu trả lời bỏ qua nó. Lookahead không khớp với cùng độ dài cho mỗi mệnh đề, trừ khi chúng kết thúc bằng $. Một cái nhìn có thể khớp với bốn nhân vật và một nhân vật khác 6. Ví dụ: (? = A *) (? = Aab) sẽ khớp với aabaaaaba
Zachary Vance

2
hãy thử chỉ sử dụng ký tự "khoảng trắng" cho toán tử "AND".

1 I'd like to match paragraphs of text.. 2. Chứa văn bản không theo thứ tự . Số 1 là mở để giải thích. Số 2 có thể được thực hiện một vài cách. Cách 1 : (?:(?:(?(1)(?!))\b(phrase1)\b.*?|(?(2)(?!))\b(phrase2)\b.*?)){2}, Cách 2: (?=.*\bphrase1\b)(?=.*\bphrase2\b)trong trường hợp này, kết hợp của đoạn trong trường hợp này không được xác định cho đến khi định nghĩa của đoạn được chính thức hóa.

Câu trả lời:


385

Sử dụng một biểu thức thông thường không tiêu thụ.

Ký hiệu điển hình (ví dụ Perl / Java) là:

(?=expr)

Điều này có nghĩa là "kết hợp expr nhưng sau đó tiếp tục khớp tại điểm so khớp ban đầu."

Bạn có thể làm nhiều thứ như bạn muốn, và đây sẽ là "và". Thí dụ:

(?=match this expression)(?=match this too)(?=oh, and this)

Bạn thậm chí có thể thêm các nhóm chụp bên trong các biểu thức không tiêu thụ nếu bạn cần lưu một số dữ liệu trong đó.


3
perl -e "q {một số thứ và thứ} = ~ / (? = some) (? = Stuff) (? = thing) /? print 'yes': in 'no'" in 'no'.
Robert P

27
Cần phải đề cập rằng ví dụ cụ thể này được gọi là khẳng định nhìn tích cực. Nó có công dụng khác ngoài "và". Lưu ý rằng văn bản không được tiêu thụ.
strager

7
Sử dụng (? =) Như thế này dẫn đến một regex không bao giờ có thể thành công. Nhưng nó sự kết hợp tương tự với |. OP chỉ sai trong những gì anh ấy nghĩ sẽ giải quyết vấn đề của mình.
Nietzche-jou

10
perl -e "q {một số thứ và những thứ} = ~ /(?=.*some)(?=.* ware)(?=.*things)/? in 'yes': in 'no'"
kriss

3
Bạn có thể vui lòng thêm một số ví dụ dễ dàng trong mã perl trong câu trả lời của bạn không?
Pithikos

343

Bạn cần sử dụng lookahead như một số người trả lời khác đã nói, nhưng lookahead phải tính đến các ký tự khác giữa từ mục tiêu của nó và vị trí khớp hiện tại. Ví dụ:

(?=.*word1)(?=.*word2)(?=.*word3)

Giao .*diện đầu tiên cho phép nó khớp với nhiều ký tự mà nó cần trước khi chuyển thành "word1". Sau đó, vị trí khớp được đặt lại và giao diện thứ hai tìm ra "word2". Đặt lại lần nữa và phần cuối cùng khớp với "word3"; vì đó là từ cuối cùng mà bạn đang kiểm tra, không cần thiết phải ở trong một cái nhìn, nhưng nó không bị tổn thương.

Để khớp toàn bộ một đoạn, bạn cần neo regex ở cả hai đầu và thêm một đoạn cuối .*để tiêu thụ các ký tự còn lại. Sử dụng ký hiệu kiểu Perl, đó sẽ là:

/^(?=.*word1)(?=.*word2)(?=.*word3).*$/m

Công cụ sửa đổi 'm' dành cho chế độ đa tuyến; nó cho phép ^$khớp tại các ranh giới đoạn ("ranh giới dòng" trong regex-speak). Trong trường hợp này, điều quan trọng là bạn không sử dụng công cụ sửa đổi, cho phép các metacharacter chấm phù hợp với các dòng mới cũng như tất cả các ký tự khác.

Cuối cùng, bạn muốn đảm bảo rằng bạn khớp toàn bộ các từ và không chỉ là các đoạn từ dài hơn, vì vậy bạn cần thêm ranh giới từ:

/^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$/m

8
Chính xác là đúng - có một hướng dẫn về điều này là tốt! ocpsoft.org/tutorials/THER-expressions/and-in-regex
Lincoln

9
Cảm ơn rất nhiều. * Điều này tạo nên sự khác biệt
Gennadiy Ryabkin

1
+1 cho câu trả lời rõ ràng và ngắn gọn thể hiện một trong những cách sử dụng tốt nhất cho giao diện (không giống như các cách sử dụng như hack để đếm tỷ lệ phần trăm trùng khớp của mật khẩu). :)
zx81

1
@Liam :. MySQL sử dụng hương vị POSIX ERE, nên không. Nó hy sinh hiệu quả các tính năng có lợi cho hiệu suất, có vẻ hợp lý với tôi. Có nhiều thông tin hơn ở đây .
Alan Moore

3
thay thế .*bằng [\s\S]*javascript nếu bạn có các dòng mới như .trong công cụ regex của javascript không khớp với các dòng mới và không thể được thực hiện với các sửa đổi
Wesley Smith

41

Nhìn vào ví dụ này:

Chúng tôi có 2 regexps A và B và chúng tôi muốn khớp cả hai, vì vậy trong mã giả, nó trông như thế này:

pattern = "/A AND B/"

Nó có thể được viết mà không cần sử dụng toán tử AND như thế này:

pattern = "/NOT (NOT A OR NOT B)/"

trong PCRE:

"/(^(^A|^B))/"

regexp_match(pattern,data)

24
Điều đó đúng về mặt logic chính thức, nhưng nó hoàn toàn không giúp được gì ở đây. Trong regexes, KHÔNG có thể khó diễn đạt hơn AND.
Alan Moore

@marvin_dpr Nó hoạt động với tôi trong CMake trong khi đề xuất khác (?=expr)thì không. Nó dường như được thực hiện phụ thuộc.
Melebius

38
Không ^có nghĩa là "bắt đầu chuỗi" trong cú pháp regex?
Tiên nữ Lambda

3
Trong regex nói chung, chỉ ^là phủ định ở đầu một lớp nhân vật. Trừ khi CMake đang làm điều gì đó thực sự thú vị (đến mức gọi ngôn ngữ khớp mẫu của họ là "regex" có thể bị coi là sai lệch hoặc không chính xác) Tôi đoán rằng thực tế nó hoạt động với bạn là một tai nạn bị cô lập.
tripleee 17/2/2015

29

Bạn có thể làm điều đó với một biểu thức thông thường nhưng có lẽ bạn sẽ muốn một số khác. Ví dụ, sử dụng một số biểu thức chính quy và kết hợp chúng trong mệnh đề if.

Bạn có thể liệt kê tất cả các hoán vị có thể với một biểu thức chính quy, như thế này (khớp a, b và c theo bất kỳ thứ tự nào):

(abc)|(bca)|(acb)|(bac)|(cab)|(cba)

Tuy nhiên, điều này làm cho một regrec rất dài và có thể không hiệu quả, nếu bạn có nhiều hơn các điều khoản.

Nếu bạn đang sử dụng một số phiên bản regrec mở rộng, như của Perl hoặc Java, họ có những cách tốt hơn để làm điều này. Các câu trả lời khác đã đề nghị sử dụng hoạt động nhìn tích cực.


10
Tôi không nghĩ rằng cách tiếp cận của bạn không hiệu quả hơn 3 lần tìm kiếm với việc quay lại thảm khốc của họ. Chắc chắn nó dài hơn để viết, nhưng lưu ý rằng bạn có thể dễ dàng tạo mẫu tự động. Lưu ý rằng bạn có thể cải thiện nó để thất bại nhanh hơn với a(bc|cb)|b(ac|ca)|c(ab|ba). Và quan trọng nhất, bạn có thể sử dụng nó với tất cả hương vị regex.
Casimir et Hippolyte

27

Toán tử AND được ẩn trong cú pháp RegExp.
Toán tử OR thay vào đó được chỉ định bằng một đường ống.
RegExp sau:

var re = /ab/;

nghĩa là chữ a chữ b.
Nó cũng hoạt động với các nhóm:

var re = /(co)(de)/;

nó có nghĩa là nhóm co nhóm de.
Thay thế (ẩn) VÀ bằng OR sẽ yêu cầu các dòng sau:

var re = /a|b/;
var re = /(co)|(de)/;

29
Thật không may, đây không phải là những gì OP yêu cầu. Điều này tìm thấy bất cứ thứ gì theo thứ tự đó, trong khi họ muốn chúng theo bất kỳ thứ tự nào. Kiểm tra câu trả lời bằng stackoverflow.com/users/20938/alan-moore dưới đây là câu trả lời đúng.
JESii

1
@JESii cảm ơn vì quan điểm của bạn, bạn đã đúng và tôi hiểu sai câu hỏi từ Hugoware, tôi đặc biệt tập trung vào câu đầu tiên của anh ấy. Câu trả lời đúng là cách sử dụng hợp lý của toán tử lookahead, như AlanMoore đã viết. Dù sao tôi nghĩ ai đó có thể thấy sự làm rõ của tôi hữu ích, như đã được nâng cấp, vì vậy tôi sẽ không vứt bỏ mọi thứ. Trân trọng.
Emanuele Del Grande

13

Trong trường hợp của bạn không thể thực hiện AND trên một số kết quả khớp? trong mã giả

regexp_match(pattern1, data) && regexp_match(pattern2, data) && ...

3
Tôi đang ở trong một tình huống mà tôi có một số mã là một bảng quy tắc dữ liệu, với một chuỗi khớp mẫu regex duy nhất để kiểm tra tính hợp lệ của quy tắc. Chuyển sang nhiều bài kiểm tra không phải là điều tôi có thể làm trong trường hợp của mình và thường là trong các trường hợp của những người khác!
Alan Wolfe

11

Tại sao không sử dụng awk?
với awk regex VÀ, HOẶC vấn đề rất đơn giản

awk '/WORD1/ && /WORD2/ && /WORD3/' myfile

9

Nếu bạn sử dụng biểu thức chính quy Perl, bạn có thể sử dụng giao diện tích cực:

Ví dụ

(?=[1-9][0-9]{2})[0-9]*[05]\b

sẽ là các số lớn hơn 100 và chia hết cho 5


8

Bạn có thể chuyển đầu ra của bạn sang regex khác. Sử dụng grep, bạn có thể làm điều này:

grep A | grep B


8

Ngoài câu trả lời được chấp nhận

Tôi sẽ cung cấp cho bạn một số ví dụ thực tế sẽ giúp mọi thứ rõ ràng hơn với một số Bạn. Ví dụ: giả sử chúng ta có ba dòng văn bản đó:

[12/Oct/2015:00:37:29 +0200] // only this + will get selected
[12/Oct/2015:00:37:x9 +0200]
[12/Oct/2015:00:37:29 +020x]

Xem demo tại đây DEMO

Điều chúng tôi muốn làm ở đây là chọn dấu + nhưng chỉ khi nó đứng sau hai số có khoảng trắng và nếu trước bốn số. Đó là những hạn chế duy nhất. Chúng tôi sẽ sử dụng biểu thức chính quy này để đạt được nó:

'~(?<=\d{2} )\+(?=\d{4})~g'

Lưu ý nếu bạn tách biểu thức nó sẽ cho bạn kết quả khác nhau.

Hoặc có lẽ bạn muốn chọn một số văn bản giữa các thẻ ... nhưng không phải các thẻ! Sau đó, bạn có thể sử dụng:

'~(?<=<p>).*?(?=<\/p>)~g'

cho văn bản này:

<p>Hello !</p> <p>I wont select tags! Only text with in</p> 

Xem demo tại đây DEMO


Câu trả lời nào là câu trả lời được chấp nhận? Vui lòng thêm một liên kết đến nó cho tương lai tôi.
James Brown

6

Thứ tự luôn được ngụ ý trong cấu trúc của biểu thức chính quy. Để thực hiện những gì bạn muốn, bạn sẽ phải khớp chuỗi đầu vào nhiều lần với các biểu thức khác nhau.

Những gì bạn muốn làm là không thể với một regrec duy nhất.


Nó không phải là không thể về mặt kỹ thuật, nhưng không đáng để thực hiện. Tôi không biết tại sao một người nào đó bị hạ thấp mặc dù ...
Robert P

13
Có lẽ bởi vì nó không chỉ có thể, nó đơn giản, giả sử hương vị regex của bạn hỗ trợ cho vẻ ngoài. Và đó là một vụ cá cược tốt; hầu hết các ngôn ngữ lập trình chính ngày nay đều hỗ trợ chúng.
Alan Moore

3

Sử dụng AND ngoài biểu thức chính quy. Trong PHP lookahead toán tử dường như không làm việc cho tôi, thay vào đó tôi đã sử dụng cái này

if( preg_match("/^.{3,}$/",$pass1) && !preg_match("/\s{1}/",$pass1))
    return true;
else
    return false;

Regex ở trên sẽ khớp nếu độ dài mật khẩu từ 3 ký tự trở lên và không có khoảng trắng trong mật khẩu.

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.