Regex Cho đến Nhưng Không Bao gồm


81

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

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

Câu trả lời:


161

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

(?:(?!X).)*

đâu Xcó thể là bất kỳ biểu thức chính quy nào.

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

[^z]*

Điều này sẽ khớp với bất kỳ thứ gì ngoại trừ zvà do đó dừng ngay trước lần tiếp theo z.

Như vậy .*?quick[^z]*sẽ phù hợp The quick fox jumps over the la.

Tuy nhiên, ngay sau khi bạn có nhiều hơn một chữ cái đơn giản để tìm kiếm (?:(?!X).)*, chẳng hạn như

(?:(?!lazy).)*- nối bất cứ thứ gì cho đến khi bắt đầu từ lazy.

Điều này đang sử dụng một khẳng định nhìn trước , cụ thể hơn là một cái nhìn tiêu cực.

.*?quick(?:(?!lazy).)*sẽ phù hợp The quick fox jumps over the.

Giải trình:

(?:        # 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 bằng các neo ranh giới từ: \bfox\bsẽ chỉ khớp với từ hoàn chỉnh foxnhưng không khớp với từ cáo trong foxy.

Ghi chú

Nếu văn bản được đối sánh cũng có thể bao gồm dấu ngắt dòng, bạn sẽ cần đặt tùy chọn "chấm khớp với tất cả" của công cụ regex của mình. Thông thường, bạn có thể đạt được điều đó bằng cách sử dụng trước (?s)regex, nhưng điều đó không hoạt động trong tất cả các công cụ regex (đặc biệt 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 đó là sử dụng bộ định lượng lười biếng. Bằng cách thêm a ?vào bộ *định lượng, nó sẽ cố gắng khớp càng ít ký tự càng tốt từ vị trí hiện tại:

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

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


+1 Câu trả lời thực sự hay, rất tiếc là không hoạt động với grep, nhưng câu trả lời này thì có.
Alexandre Lavoie

@AlexandreLavoie: Thật thú vị. Tại sao cái kia nên làm việc mà không phải cái này? Cả hai đều sử dụng xác nhận nhìn trước. Có lẽ chỉ vì nhóm (?:...)không chụp? Nó hoạt động với ((?!X).)*?
Tim Pietzcker

1
Thực sự không biết, tôi không phải là chuyên gia regex cũng như grep. Tôi đang sử dụng grepđể lọc các yêu cầu chỉ cho một cơ sở dữ liệu từ mysql bin transformet trong sql. Đây là con thú:grep -Po "(?s)use database_to_keep(.*?)(?=^use)" mysql-bin.000045.sql > filtered.sql
Alexandre Lavoie

Trông giống như một cuộc xung đột bash kể từ khi tôi nhấn Upquan trọng, lệnh cuối cùng không phải là người tôi đã sử dụng:grep -Po "(?s)use database_to_keep(.*?)(?:(?!^use).)*" mysql-bin.000045.sql > filtered.sql
Alexandre Lavoie

1
Chỉnh sửa tốt, @Tim, chỉ cần thêm $thay thế: thay thế .*?(?=X)bằng.*?(?=X|$)
Wiktor Stribiżew

15

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

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

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

Đây là mẫu mã C #:

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

0

Thử cái này

(.*?quick.*?)z

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