gì hầu hết mọi người không cần xem xét khi tiếp cận câu hỏi như thế này là những gì xảy ra khi regex không thể tìm thấy kết quả phù hợp. Đó là khi hố hoạt động sát thủ có nhiều khả năng xuất hiện nhất. Ví dụ, lấy ví dụ của Tim, nơi bạn đang tìm kiếm một cái gì đó như <tag>Hello!
. Hãy xem xét những gì xảy ra với:
<.*?>Hello!
Động cơ regex tìm thấy một <
và nó nhanh chóng tìm thấy một kết thúc >
, nhưng không >Hello!
. Vì vậy, .*?
tiếp tục tìm kiếm >
rằng là theo sau là Hello!
.Nếu không có một, nó sẽ đi tất cả các cách để kết thúc của tài liệu trước khi nó cho lên. Sau đó, công cụ regex tiếp tục quét cho đến khi tìm thấy một số khác <
và thử lại. Chúng tôi đã biết cách điều đó sẽ xảy ra, nhưng động cơ regex thường không; nó đi qua cùng một rigamarole với mỗi <
trong tài liệu. Bây giờ xem xét các regex khác:
<[^>]*>Hello!
Như trước đây, nó nhanh chóng phù hợp với từ <
đến >
, nhưng không phù hợp với Hello!
. Nó sẽ quay trở lại số <
, sau đó thoát và bắt đầu quét tìm một số <
khác. Nó vẫn sẽ kiểm tra mọi <
như regex đầu tiên đã làm, nhưng nó sẽ không tìm kiếm tất cả các cách để kết thúc của tài liệu mỗi khi nó tìm thấy một.
Nhưng thậm chí còn tệ hơn thế. Nếu bạn nghĩ về nó, .*?
có hiệu quả tương đương với một lookahead tiêu cực. Nó nói rằng "Trước khi tiêu thụ nhân vật tiếp theo, hãy đảm bảo phần còn lại của regex không thể khớp ở vị trí này." Nói cách khác,
/<.*?>Hello!/
... tương đương với:
/<(?:(?!>Hello!).)*(?:>Hello!|\z(*FAIL))/
Vì vậy, ở mọi vị trí mà bạn đang thực hiện, chứ không phải chỉ là một nỗ lực trận đấu bình thường, nhưng một lookahead đắt hơn nhiều. (Đó là ít nhất hai lần như tốn kém, vì lookahead có để quét ít nhất một nhân vật, sau đó các .
đi trước và tiêu thụ một ký tự.)
((*FAIL)
là một trong những backtracking-control verbs (còn được hỗ trợ trong PHP). |\z(*FAIL)
phương tiện Perl "hoặc đến cuối tài liệu và từ bỏ".)
Cuối cùng, có một lợi thế khác của phương pháp tiếp cận lớp nhân vật phủ định. Trong khi nó không (như @Bart chỉ ra) đóng vai trò như lượng hóa là sở hữu, không có gì để ngăn chặn bạn từ làm là nó sở hữu, nếu hương vị của bạn hỗ trợ nó:
/<[^>]*+>Hello!/
... hoặc quấn nó trong một nhóm nguyên tử:
/(?><[^>]*>)Hello!/
Không chỉ những regex này sẽ không bao giờ quay trở lại không cần thiết, họ không phải lưu thông tin trạng thái có thể quay ngược lại được.
Lưu ý rằng '[^>] *' sẽ chỉ _not_ quay lại nếu nó được theo sau bởi những gì nằm trong lớp phủ định ('[^>] *>' trong trường hợp này). Kobi, tôi biết bạn biết và có lẽ có nghĩa là điều này, nhưng muốn chắc chắn rằng những người khác không nghĩ rằng '[^>] *' và '[^>] * +' (sở hữu) là như nhau. Bên cạnh đó, câu trả lời hay! –
@Bart - Điểm tốt, đó là một sự lựa chọn của người nghèo từ. Cảm ơn! – Kobi