Làm thế nào để khớp, nhưng không bắt, một phần của regex?


209

Tôi có một danh sách các chuỗi. Một số trong số họ có hình thức 123-...456. Phần biến "..." có thể là:

  • chuỗi "apple" theo sau là dấu gạch nối, vd 123-apple-456
  • chuỗi "chuối" theo sau là dấu gạch nối, vd 123-banana-456
  • một chuỗi trống, ví dụ 123-456(lưu ý chỉ có một dấu gạch nối)

Bất kỳ từ nào khác ngoài "táo" hoặc "chuối" đều không hợp lệ.

Đối với ba trường hợp này, tôi muốn lần lượt ghép "táo", "chuối" và "". Lưu ý rằng tôi không bao giờ muốn chụp dấu gạch nối, nhưng tôi luôn muốn khớp nó. Nếu chuỗi không có dạng 123-...456như mô tả ở trên, thì không có kết quả khớp nào cả.

Làm thế nào để tôi viết một biểu thức chính quy để làm điều này? Giả sử tôi có một hương vị cho phép các nhóm lookahead, lookbehind, lookaround và không bắt giữ.


Quan sát chính ở đây là khi bạn có "quả táo" hoặc "quả chuối", bạn cũng phải có dấu gạch nối, nhưng bạn không muốn ghép nó. Và khi bạn khớp chuỗi trống, bạn không được có dấu gạch nối. Một regex đóng gói khẳng định này sẽ là đúng, tôi nghĩ vậy.


Bạn muốn phù hợp với tất cả mọi thứ ngoại trừ dấu gạch ngang?
BrunoLM

Câu trả lời:


285

Cách duy nhất để không nắm bắt được điều gì đó là sử dụng các xác nhận nhìn xung quanh :

(?<=123-)((apple|banana)(?=-456)|(?=456))

Bởi vì ngay cả với các nhóm không bắt giữ(?:…) , toàn bộ biểu thức chính quy sẽ nắm bắt nội dung phù hợp của chúng. Nhưng biểu thức chính quy này chỉ khớp applehoặc banananếu nó đứng trước 123-và theo sau -456, hoặc nó khớp với chuỗi trống nếu nó đứng trước 123-và theo sau 456.

|Lookaround  |    Name      |        What it Does                       |
-----------------------------------------------------------------------
|(?=foo)     |   Lookahead  | Asserts that what immediately FOLLOWS the |
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?<=foo)    |   Lookbehind | Asserts that what immediately PRECEDES the|
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?!foo)     |   Negative   | Asserts that what immediately FOLLOWS the |
|            |   Lookahead  |  current position in the string is NOT foo|
-------------------------------------------------------------------------
|(?<!foo)    |   Negative   | Asserts that what immediately PRECEDES the|
|            |   Lookbehind |  current position in the string is NOT foo|
-------------------------------------------------------------------------

1
+1 - Trong trường hợp này, bạn có thể giải quyết vấn đề đó bằng cách sử dụng nhóm 1 thay vì nhóm 0, nhưng đây là một sự khác biệt xuất sắc (và tinh tế!).
Bến Trống

@Ben Blank: Điều này hoàn toàn phụ thuộc vào cách diễn giải của trận đấu và cách bắt giữ.
Gumbo

8
Không được hỗ trợ trong JavaScript, yay ! sẽ rất tuyệt nếu có một phương thức thân thiện với JS, nhưng không tệ chút nào, +0,5 (làm tròn lên; D)
GiantCowFilms

Yêu khẳng định xung quanh! Chúng cũng hoạt động rất tốt với Ruby.
Rots

giải pháp hoàn hảo, tôi thích điều này
Trần Quang Hiệp

15

Cập nhật: Cảm ơn Germán Rodríguez Herrera!

Trong javascript hãy thử: /123-(apple(?=-)|banana(?=-)|(?!-))-?456/

Hãy nhớ rằng kết quả là trong nhóm 1

Trình diễn gỡ lỗi


8

Thử:

123-(?:(apple|banana|)-|)456

Điều đó sẽ khớp apple, bananahoặc một chuỗi trống và theo sau nó sẽ có một dấu gạch nối 0 hoặc 1. Tôi đã sai về việc không có nhu cầu cho một nhóm bắt giữ. Tôi thật ngốc.


Điều này không đúng vì nó khớp, ví dụ: "123-dừa-456".
David Stone

Nghĩ rằng bạn muốn nó chung chung hơn ... cố định.
Thomas

5

Tôi đã sửa đổi một trong những câu trả lời (bởi @ op1ekun):

123-(apple(?=-)|banana(?=-)|(?!-))-?456

Lý do là câu trả lời từ @ op1ekun cũng khớp "123-apple456", không có dấu gạch nối sau quả táo.


3

Thử cái này:

/\d{3}-(?:(apple|banana)-)?\d{3}/

1
Điều này không đúng vì nó khớp, ví dụ: "123-dừa-456".
David Stone

@david: nó khác với ví dụ "chuối" của bạn như thế nào?
SilentGhost

@SilentGhost: Tôi chỉ muốn chụp applehoặc bananahoặc "". Tất cả các giá trị khác là không hợp lệ, như tôi đã nêu.
David Stone

sry, trong trường hợp đó: / \ d {3} - (? :( apple | chuối) -)? \ d {3} /
slosd

1
Điều mà ví dụ này cho thấy là có thể có một nhóm không bắt giữ mà không cần sử dụng lookahead và lookbehind.
Vince Panuccio

0

Một biến thể của biểu thức bởi @Gumbo sử dụng \Kđể đặt lại các vị trí khớp để ngăn việc đưa các khối số vào trận đấu. Có thể sử dụng trong hương vị regex PCRE.

123-\K(?:(?:apple|banana)(?=-456)|456\K)

Diêm:

Match 1  apple
Match 2  banana
Match 3

-3

Cho đến nay, đơn giản nhất (làm việc cho python) là '123-(apple|banana)-?456'.


1
Điều này sẽ phù hợp 123-apple456để nó không chính xác.
Loren
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.