Regex chính xác n HOẶC m lần


105

Hãy xem xét biểu thức chính quy sau, ở đâu Xbất kỳ regex nào .

X{n}|X{m}

Regex này sẽ kiểm tra xem có Xxảy ra chính xác n hay không m.

Có bộ định lượng regex nào có thể kiểm tra Xchính xác một lần nhay một lần xảy ra mkhông?


Không. Hai lần xuất hiện Xlà tốt nhất bạn có thể nhận được cho tổng thể m, n.
John Dvorak

Nếu đây là vấn đề của tôi, tôi sẽ thử tham chiếu ngược regex và sẽ bắt đầu với (X)\1{n-1}(?:\1{m-n-1}). Tôi biết điều này phù hợp Xvới ít nhất một lần nhưng chỉ để bắt đầu, hãy thử điều đơn giản này sau đó tinh chỉnh bằng cách sử dụng hình ảnh đầu trang hoặc hình ảnh tương tự thay vì (X).
nalply

Câu trả lời:


91

Không có một định lượng nào có nghĩa là "chính xác m hoặc n lần". Cách bạn đang làm là ổn.

Một thay thế là:

X{m}(X{k})?

ở đâu m < nklà giá trị của n-m.


67

Đây là danh sách đầy đủ các bộ định lượng (tham khảo http://www.regular-expressions.info/reference.html ):

  • ?, ??- 0 hoặc 1 lần xuất hiện ( ??lười biếng, ?tham lam)
  • *, *?- bất kỳ số lần xuất hiện nào
  • +, +?- ít nhất một lần xuất hiện
  • {n}- chính xác nlần xuất hiện
  • {n,m}- nđể mlần xuất hiện, bao gồm
  • {n,m}?- nsắp mxảy ra, lười biếng
  • {n,}, {n,}?- ít nhất là nsự xuất hiện

Để nhận được "chính xác N hoặc M", bạn cần viết regex đã định lượng hai lần, trừ khi m, n là đặc biệt:

  • X{n,m} nếu m = n+1
  • (?:X{n}){1,2} nếu m = 2n
  • ...

1
Tại sao lại ?:cần trong m = 2nví dụ if ? Có vẻ hoạt động tốt mà không có nó đối với tôi.
erb

7
@erb nếu bạn bỏ qua ?:, nhóm sẽ trở thành nhóm bắt. Ngoài việc công cụ regex ghi nhớ những thứ không cần thiết, nếu bạn có các nhóm chụp sau nhóm này, ID của họ sẽ thay đổi. Nếu bạn sử dụng regex của mình để thay thế, bạn sẽ phải điều chỉnh sự thay thế.
John Dvorak


3

TLDR; (?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

Có vẻ như bạn muốn "xn times" hoặc "xm times", tôi nghĩ bản dịch theo nghĩa đen sang regex sẽ (x{n}|x{m}). giống như thế này https://regex101.com/r/vH7yL5/1

hoặc, trong trường hợp bạn có thể có một chuỗi nhiều hơn m "x" s (giả sử m> n), bạn có thể thêm 'theo sau không "x"' và 'theo sau không "x", dịch sang [^x](x{n}|x{m})[^x]nhưng điều đó sẽ giả sử rằng luôn có một ký tự đứng sau và sau bạn "x" s. Như bạn có thể thấy ở đây: https://regex101.com/r/bB2vH2/1

bạn có thể thay đổi nó thành (?:[^x]|^)(x{n}|x{m})(?:[^x]|$), dịch thành "không theo sau 'x' hoặc sau dòng bắt đầu" và "theo sau là không 'x' hoặc theo sau là cuối dòng". Tuy nhiên, nó sẽ không khớp với hai chuỗi chỉ có một ký tự giữa chúng (vì trận đầu tiên sẽ yêu cầu một ký tự đứng sau và chuỗi thứ hai là một ký tự trước đó) như bạn có thể xem tại đây: https://regex101.com/r/ oC5oJ4 / 1

Cuối cùng, để so khớp từ xa với một ký tự, bạn có thể thêm một cái nhìn tích cực về phía trước (? =) Vào "không 'x' sau" hoặc một cái nhìn tích cực phía sau (? <=) Vào "không 'x' trước", như thế này: https://regex101.com/r/mC4uX3/1

(?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

Bằng cách này, bạn sẽ chỉ đối sánh chính xác số 'x mà bạn muốn.


1

Xem qua câu trả lời của Enharedly, họ nói rằng biểu cảm áp chót của họ sẽ không khớp với các chuỗi chỉ có một ký tự giữa họ. Có một cách dễ dàng để khắc phục điều này mà không cần sử dụng nhìn trước / nhìn sau, đó là thay thế ký tự bắt đầu / kết thúc bằng ký tự ranh giới. Điều này cho phép bạn so khớp với các ranh giới từ bao gồm bắt đầu / kết thúc. Do đó, biểu thức thích hợp phải là:

(?:[^x]|\b)(x{n}|x{m})(?:[^x]|\b)

Như bạn có thể thấy ở đây: https://regex101.com/r/oC5oJ4/2 .


1
Thật tuyệt, tôi không quen với cách regex xử lý các ranh giới. Vấn đề duy nhất với phương pháp này là khi bạn đang sử dụng ranh giới không chuẩn. Kể về cái nhìn: regex101.com/r/j0nkeo/1regex101.com/r/4Ix7Dr/1
Enharged

1
@Enharedly - đó là một điểm tốt, có vẻ là một vấn đề với nhiều nhóm đối sánh chồng chéo lên nhau. Đó là một tình huống mà bạn cần phải sử dụng quan sát phía sau.
rozza2058

1

Bài rất cũ, nhưng tôi muốn đóng góp sth có thể giúp ích. Tôi đã thử nó chính xác theo cách được nêu trong câu hỏi và nó hoạt động nhưng có một điểm bắt buộc: Thứ tự của các số lượng rất quan trọng. Xem xét điều này:

#[a-f0-9]{6}|#[a-f0-9]{3}

Điều này sẽ tìm thấy tất cả các lần xuất hiện của mã màu hex (chúng dài 3 hoặc 6 chữ số). Nhưng khi tôi lật nó lại như thế này

#[a-f0-9]{3}|#[a-f0-9]{6}

nó sẽ chỉ tìm 3 chữ số hàng đơn vị hoặc 3 chữ số đầu tiên của 6 chữ số hàng đơn vị. Điều này có ý nghĩa và một chuyên gia Regex có thể phát hiện ra điều này ngay lập tức, nhưng đối với nhiều người, đây có thể là một hành vi đặc biệt. Có một số tính năng Regex nâng cao có thể tránh bẫy này bất kể thứ tự như thế nào, nhưng không phải ai cũng hiểu sâu về các mẫu Regex.

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.