2010-10-03 27 views
38

Đối với regex cú pháp tìm kiếm cho đến khi nào nhưng không bao gồm? Kinda thích:Regex cho đến khi không bao gồm

Haystack: 
The quick red fox jumped over the lazy brown dog 

Expression: 
.*?quick -> and then everything until it hits the letter "z" but do not include z 

Trả lời

104

Cách rõ ràng nói "tìm kiếm cho đến khi X nhưng không bao gồm X" là:

(?:(?!X).)* 

nơi X thể được bất kỳ biểu thức chính quy.

Trong trường hợp của bạn, tuy nhiên, điều này có thể quá mức cần thiết - đây là cách dễ nhất sẽ

[^z]* 

này sẽ phù hợp bất cứ điều gì ngoại trừ z và do đó dừng lại ngay trước khi tới z.

Vì vậy, .*?quick[^z]* sẽ khớp với The quick fox jumps over the la.

Tuy nhiên, ngay sau khi bạn có nhiều hơn một ký tự đơn giản để tìm cho ra, (?:(?!X).)* đi vào chơi, ví dụ

(?:(?!lazy).)* - phù hợp với bất cứ điều gì cho đến khi bắt đầu của từ lazy.

Điều này đang sử dụng một số lookahead assertion, cụ thể hơn là một cái nhìn tiêu cực.

.*?quick(?:(?!lazy).)* sẽ khớp với The quick fox jumps over the.

Giải thích:

(?:  # Match the following but do not capture it: 
(?!lazy) # (first assert that it's not possible to match "lazy" here 
.   # then match any character 
)*   # end of group, zero or more repetitions. 

Hơn nữa, khi tìm kiếm từ khóa, bạn có thể muốn bao quanh chúng với neo ranh giới từ: \bfox\b sẽ chỉ phù hợp với từ hoàn chỉnh fox nhưng không phải là con cáo trong foxy.

Note

Nếu văn bản để được xuất hiện cũng có thể bao gồm linebreaks, bạn sẽ cần phải đặt "dấu chấm phù hợp với tất cả" tùy chọn động cơ regex của bạn. Thông thường, bạn có thể đạt được điều đó bằng cách thêm (?s) vào regex, nhưng điều đó không hoạt động trong tất cả các công cụ regex (đáng chú ý là JavaScript).

giải pháp thay thế:

Trong nhiều trường hợp, bạn cũng có thể sử dụng một giải pháp đơn giản hơn, dễ đọc hơn mà sử dụng một lượng hóa lười biếng. Bằng cách thêm một ? đến * lượng hóa, nó sẽ cố gắng để phù hợp càng ít nhân vật càng tốt từ vị trí hiện tại:

.*?(?=(?:X)|$) 

sẽ phù hợp với bất kỳ số lượng nhân vật, dừng lại ngay trước X (mà có thể là bất kỳ regex) hoặc cuối chuỗi (nếu X không khớp). Bạn cũng có thể cần phải đặt tùy chọn "chấm khớp với tất cả" để làm việc này.(Lưu ý: Tôi đã thêm một tổ chức phi chụp xung quanh X để chắc chắn cô lập nó khỏi luân phiên)

+0

+1 Really nice câu trả lời, tiếc là không làm việc với 'grep', nhưng điều này [trả lời] (http://stackoverflow.com/a/5979402/ 354831). –

+0

@AlexandreLavoie: Thú vị. Tại sao người khác nên làm việc chứ không phải cái này? Cả hai đều sử dụng xác nhận lookahead. Có lẽ nó chỉ vì nhóm không bắt giữ '(?: ...) '? Nó có hoạt động với '((?! X).) *'? –

+1

Thực sự không biết, tôi không phải là chuyên gia regex hay grep. Tôi đã sử dụng 'grep' để lọc các yêu cầu chỉ có một cơ sở dữ liệu từ mysql bin transformet trong sql. Đây là con thú: 'grep -Po" (? S) sử dụng database_to_keep (. *?) (? =^Sử dụng) "mysql-bin.000045.sql> filtration.sql' –

0

Hãy thử điều này

(.*?quick.*?)z 
+0

Điều này bao gồm "z" trong trận đấu, chính xác là những gì người hỏi muốn tránh. Có lẽ regex được dự định là một thuật ngữ trong một '|' thay thế và regex thay thế được sử dụng để thực hiện nhiều kết quả phù hợp. Nếu "z" là phần đầu của chuỗi sẽ được so khớp bởi ** một cụm từ ** khác trong phần tử thay thế, thì trận đấu này sẽ bị hủy vì "z" đã bị tiêu thụ bởi trận đấu hiện tại. –

5

Một lookahead regex syntax có thể giúp bạn đạt được mục tiêu của bạn. Vì vậy, một regex ví dụ của bạn là

.*?quick.*?(?=z) 

Và điều quan trọng là bạn phải chú ý đến .*? khớp lười biếng trước (?=z) lookahead: các biểu hiện phù hợp với một chuỗi con cho đến khi một xuất hiện đầu tiên của bức thư z.

Dưới đây là C# mẫu mã:

const string text = "The quick red fox jumped over the lazy brown dogz"; 

string lazy = new Regex(".*?quick.*?(?=z)").Match(text).Value; 
Console.WriteLine(lazy); // The quick red fox jumped over the la 

string greedy = new Regex(".*?quick.*(?=z)").Match(text).Value; 
Console.WriteLine(greedy); // The quick red fox jumped over the lazy brown dog 
Các vấn đề liên quan