Làm thế nào tôi có thể nhận ra một regex độc ác?


83

Gần đây, tôi đã biết về các cuộc tấn công Từ chối Dịch vụ Biểu thức chính quy và quyết định loại bỏ tận gốc cái gọi là các mẫu regex 'ác' ở bất cứ nơi nào tôi có thể tìm thấy chúng trong cơ sở mã của mình - hoặc ít nhất là những mẫu được sử dụng trên đầu vào của người dùng. Các ví dụ được đưa ra tại liên kết OWASP ở trên và wikipedia rất hữu ích, nhưng chúng không thực hiện tốt việc giải thích vấn đề bằng các thuật ngữ đơn giản.

Mô tả về ác ma regexes, từ wikipedia :

  • biểu thức chính quy áp dụng lặp lại ("+", "*") cho một biểu thức con phức tạp;
  • đối với biểu thức con được lặp lại, tồn tại một kết quả phù hợp cũng là hậu tố của một kết quả hợp lệ khác.

Với các ví dụ, một lần nữa từ wikipedia :

  • (a+)+
  • ([a-zA-Z]+)*
  • (a|aa)+
  • (a|a?)+
  • (.*a){x} cho x> 10

Đây có phải là một vấn đề không có lời giải thích đơn giản hơn không? Tôi đang tìm kiếm thứ gì đó có thể giúp tránh sự cố này dễ dàng hơn trong khi viết regexes hoặc tìm chúng trong cơ sở mã hiện có.


7
Một liên kết về chủ đề này là một trong những điều này: regular-expressions.info/catastrophic.html
Daniel Hilgarth

1
Đây là một công cụ để thực hiện phân tích tĩnh trên các biểu thức chính quy để phát hiện các vấn đề nghi ngờ về ReDoS: cs.bham.ac.uk/~hxt/research/rxxr.shtml
tripleee

Liên kết do @tripleee cung cấp dường như có liên kết bị hỏng đến công cụ RXXR. Đây là nhân bản GitHub: github.com/ConradIrwin/rxxr2
Mike Hill

3
Ngoài ra, đối với những người tò mò, có vẻ như các tác giả của công cụ RXXR ban đầu đã thay thế nó bằng RXXR2. Trang mới của họ được lưu trữ tại đây và hiện có liên kết đang hoạt động tới nguồn RXXR2
Mike Hill,

Câu trả lời:


76

Tại sao Ác ma lại là một vấn đề?

Bởi vì máy tính làm chính xác những gì bạn yêu cầu chúng làm, ngay cả khi nó không phải như ý bạn hoặc hoàn toàn không hợp lý. Nếu bạn yêu cầu công cụ Regex chứng minh rằng, đối với một số đầu vào nhất định, có hoặc không phù hợp với một mẫu nhất định, thì công cụ sẽ cố gắng thực hiện điều đó bất kể có bao nhiêu kết hợp khác nhau phải được kiểm tra.

Đây là một mẫu đơn giản được lấy cảm hứng từ ví dụ đầu tiên trong bài đăng của OP:

^((ab)*)+$

Cho đầu vào:

abababababababababababab

Công cụ regex thử một cái gì đó giống như (abababababababababababab)và một kết quả phù hợp được tìm thấy trong lần thử đầu tiên.

Nhưng sau đó chúng tôi ném cờ lê khỉ vào:

abababababababababababab a

Đầu tiên động cơ sẽ thử (abababababababababababab)nhưng không thành công vì phần phụ đó a. Điều này gây ra bracktracking thảm khốc, bởi vì mô hình của chúng tôi (ab)*, thể hiện thiện chí, sẽ phát hành một trong các hình ảnh chụp của nó (nó sẽ "quay ngược") và để mô hình bên ngoài thử lại. Đối với công cụ regex của chúng tôi, nó trông giống như sau:

(abababababababababababab)- Không
(ababababababababababab)(ab)- Không
(abababababababababab)(abab)- Không
(abababababababababab)(ab)(ab)- Không
(ababababababababab)(ababab)- Không
(ababababababababab)(abab)(ab)- Không
(ababababababababab)(ab)(abab)- Không
(ababababababababab)(ab)(ab)(ab)- Không
(abababababababab)(abababab)- Không
(abababababababab)(ababab)(ab)- Không
(abababababababab)(abab)(abab)- Không
(abababababababab)(abab)(ab)(ab)- Không
(abababababababab)(ab)(ababab)- Không
(abababababababab)(ab)(abab)(ab)- Không
(abababababababab)(ab)(ab)(abab)- Không
(abababababababab)(ab)(ab)(ab)(ab)- Không
(ababababababab)(ababababab)- Không
(ababababababab)(abababab)(ab)- Không
(ababababababab)(ababab)(abab)- Không
(ababababababab)(ababab)(ab)(ab)- Không
(ababababababab)(abab)(abab)(ab)- Không
(ababababababab)(abab)(ab)(abab)- Không
(ababababababab)(abab)(ab)(ab)(ab)- Không
(ababababababab)(ab)(abababab)- Không
(ababababababab)(ab)(ababab)(ab)- Không - Không - Không - Không
(ababababababab)(ab)(abab)(abab)- Không
(ababababababab)(ab)(abab)(ab)(ab)- Không
(ababababababab)(ab)(ab)(ababab)- Không
(ababababababab)(ab)(ab)(abab)(ab) - Không
(ababababababab)(ab)(ab)(ab)(abab)- Không
(ababababababab)(ab)(ab)(ab)(ab)(ab)- Không
                              ...
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abababab) - Không
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ababab)(ab)- Không
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abab)(abab)- Không
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abab)(ab)(ab)- Không
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ababab)- Không
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abab)(ab)- Không
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(abab)- Không
(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)(ab)- Không

Số lượng các kết hợp có thể có tỷ lệ theo cấp số nhân với độ dài của đầu vào và trước khi bạn biết điều đó, công cụ regex đang tiêu thụ tất cả tài nguyên hệ thống của bạn khi cố gắng giải quyết vấn đề này cho đến khi, khi sử dụng hết mọi tổ hợp thuật ngữ có thể, nó cuối cùng đã bỏ báo cáo "Không có kết quả phù hợp." Trong khi đó máy chủ của bạn đã biến thành một đống kim loại nóng chảy đang cháy.

Làm thế nào để phát hiện ra các Regexes xấu xa

Nó thực sự rất phức tạp. Tôi đã tự viết một vài câu, mặc dù tôi biết chúng là gì và nói chung là làm thế nào để tránh chúng. Xem Regex mất nhiều thời gian đáng ngạc nhiên . Gói mọi thứ bạn có thể vào một nhóm nguyên tử có thể giúp ngăn ngừa vấn đề bẻ khóa ngược. Về cơ bản, nó yêu cầu công cụ regex không truy cập lại một biểu thức đã cho - "khóa bất kỳ thứ gì bạn đã khớp trong lần thử đầu tiên". Tuy nhiên, lưu ý rằng biểu thức nguyên tử không ngăn chặn backtracking bên trong biểu thức, do đó ^(?>((ab)*)+)$vẫn nguy hiểm, nhưng ^(?>(ab)*)+$an toàn (nó sẽ khớp (abababababababababababab)và sau đó từ chối từ bỏ bất kỳ ký tự nào đã khớp của nó, do đó ngăn chặn backtracking thảm khốc).

Thật không may, một khi nó được viết, thực sự rất khó để tìm ra ngay lập tức hoặc nhanh chóng một regex vấn đề. Cuối cùng, nhận ra một regex xấu cũng giống như nhận ra bất kỳ mã xấu nào khác - cần rất nhiều thời gian và kinh nghiệm và / hoặc một sự kiện thảm khốc.


Điều thú vị là, vì câu trả lời này được viết lần đầu tiên, một nhóm nghiên cứu tại Đại học Texas ở Austin đã xuất bản một bài báo mô tả sự phát triển của một công cụ có khả năng thực hiện phân tích tĩnh các Biểu thức chính quy với mục đích rõ ràng là tìm ra các mẫu "xấu" này. Công cụ này được phát triển để phân tích các chương trình Java, nhưng tôi nghi ngờ rằng trong những năm tới, chúng ta sẽ thấy nhiều công cụ hơn được phát triển xung quanh anaylsing và phát hiện các mẫu có vấn đề trong JavaScript và các ngôn ngữ khác, đặc biệt là khi tỷ lệ các cuộc tấn công ReDoS tiếp tục tăng .

Phát hiện tĩnh các lỗ hổng DoS trong các chương trình sử dụng Biểu thức chính quy
Valentin Wüstholz, Oswaldo Olivo, Marijn JH Heule và Isil Dillig
Đại học Texas tại Austin


Đây là một câu trả lời rất tốt trong việc mô tả / tại sao / ví dụ regex mất nhiều thời gian, nhưng tôi đang tìm kiếm một vài quy tắc mà một người có thể nội dung để giúp nhận ra regex vấn đề.
Mike Partridge

4
Biết "tại sao" là bước quan trọng nhất để tránh viết regex "ác". Thật không may, một khi nó được viết ra, thực sự rất khó để tìm ra ngay lập tức hoặc nhanh chóng một regex vấn đề. Nếu bạn muốn sửa chữa hàng loạt, nhóm nguyên tử thường là cách tốt nhất, nhưng điều đó có thể có tác động đáng kể đến các mẫu mà regex sẽ khớp. Cuối cùng, việc nhận ra một regex xấu cũng giống như regex bất kỳ mã xấu nào khác - nó cần rất nhiều kinh nghiệm, nhiều thời gian và / hoặc một sự kiện thảm khốc.
JDB vẫn nhớ Monica

Đây là lý do tại sao sở thích của tôi dành cho các động cơ regex không hỗ trợ bẻ khóa ngược mà không cần người dùng ép buộc. IE lex / flex.
Spencer Rathbun

@MikePartridge đó là vấn đề lý thuyết cổ điển phổ biến của CNTT, để quyết định xem một số mã sẽ lặp vô hạn hay dừng lại là một dạng vấn đề hoàn toàn NP. Với regex, bạn có thể đoán / bắt một số trong số chúng bằng cách tìm kiếm các mẫu / quy tắc nhất định, nhưng trừ khi bạn thực hiện một số phân tích NP-đầy đủ nặng, bạn sẽ không bao giờ nắm bắt được tất cả. Một số tùy chọn: 1) không bao giờ cho phép người dùng nhập regexp vào máy chủ của bạn. 2) cấu hình công cụ regexp để kết thúc tính toán đủ sớm (nhưng kiểm tra regex hợp lệ trong mã của bạn vẫn hoạt động, ngay cả với các giới hạn nghiêm ngặt). 3) chạy mã regex trong luồng ưu tiên thấp với giới hạn cpu / mem.
Ped7g

1
@MikePartridge - gần đây đã xem một bài báo về một số công cụ mới đang được phát triển để phát hiện tĩnh các regex có vấn đề này. Những điều thú vị ... Tôi nghĩ nó sẽ đáng theo dõi.
JDB vẫn nhớ Monica

12

Cái mà bạn gọi là regex "ác" là một regex biểu hiện vết nứt ngược thảm khốc . Trang được liên kết (mà tôi đã viết) giải thích khái niệm chi tiết. Về cơ bản, việc bẻ khóa ngược thảm khốc xảy ra khi một regex không khớp và các hoán vị khác nhau của cùng một regex có thể tìm thấy một phần khớp. Công cụ regex sau đó thử tất cả các hoán vị đó. Nếu bạn muốn xem lại mã của mình và kiểm tra các regex của mình, đây là 3 vấn đề chính cần xem xét:

  1. Các lựa chọn thay thế phải loại trừ lẫn nhau. Nếu nhiều lựa chọn thay thế có thể khớp với cùng một văn bản thì công cụ sẽ thử cả hai nếu phần còn lại của regex không thành công. Nếu các lựa chọn thay thế nằm trong một nhóm được lặp đi lặp lại, bạn có một sự cố ngược thảm khốc. Một ví dụ cổ điển là (.|\s)*khớp với bất kỳ lượng văn bản nào khi hương vị regex không có chế độ "dấu chấm khớp với ngắt dòng". Nếu đây là một phần của regex dài hơn thì một chuỗi chủ đề với khoảng cách đủ dài (được khớp bởi cả hai .\s) sẽ phá vỡ regex. Cách khắc phục là sử dụng(.|\n)* để làm cho các lựa chọn thay thế loại trừ lẫn nhau hoặc thậm chí tốt hơn để cụ thể hơn về những ký tự nào thực sự được phép, chẳng hạn như [\r\n\t\x20-\x7E]đối với bảng in ASCII, tab và ngắt dòng.

  2. Các mã thông báo được định lượng theo thứ tự phải loại trừ lẫn nhau với nhau hoặc loại trừ lẫn nhau những gì có giữa chúng. Nếu không, cả hai có thể khớp với cùng một văn bản và tất cả các kết hợp của hai bộ định lượng sẽ được thử khi phần còn lại của regex không khớp. Một ví dụ cổ điển là a.*?b.*?ckết hợp 3 thứ với "bất cứ thứ gì" giữa chúng. Khi ckhông thể so khớp đầu tiên .*?sẽ mở rộng từng ký tự cho đến cuối dòng hoặc tệp. Đối với mỗi lần mở rộng thứ hai .*?sẽ mở rộng từng ký tự để khớp với phần còn lại của dòng hoặc tệp. Cách khắc phục là nhận ra rằng bạn không thể có "bất cứ thứ gì" giữa chúng. Lần chạy đầu tiên cần dừng lại bvà lần chạy thứ hai cần dừng lại ở c. Với các ký tự đơna[^b]*+b[^c]*+clà một giải pháp dễ dàng. Vì bây giờ chúng ta dừng lại ở dấu phân cách, chúng ta có thể sử dụng các bộ định lượng sở hữu để tăng hiệu suất hơn nữa.

  3. Một nhóm chứa mã thông báo có bộ định lượng không được có bộ định lượng của riêng nó trừ khi mã thông báo được định lượng bên trong nhóm chỉ có thể được khớp với một thứ khác loại trừ lẫn nhau với nó. Điều đó đảm bảo rằng không có cách nào mà số lần lặp ít hơn của bộ định lượng bên ngoài với nhiều lần lặp hơn của bộ định lượng bên trong có thể khớp với cùng một văn bản giống như nhiều lần lặp hơn của bộ định lượng bên ngoài với ít lần lặp hơn của bộ định lượng bên trong. Đây là vấn đề được minh họa trong câu trả lời của JDB.

Trong khi viết câu trả lời, tôi quyết định rằng điều này xứng đáng với một bài báo đầy đủ trên trang web của tôi . Điều này hiện cũng đang trực tuyến.


10

Tôi sẽ tóm tắt nó là "Một sự lặp lại của một sự lặp lại". Ví dụ đầu tiên bạn liệt kê là một ví dụ hay, vì nó nêu "chữ cái a, một hoặc nhiều lần liên tiếp. Điều này có thể xảy ra một hoặc nhiều lần liên tiếp".

Điều cần tìm trong trường hợp này là sự kết hợp của các bộ định lượng, chẳng hạn như * và +.

Một điều hơi tinh tế hơn cần tìm là cái thứ ba và thứ tư. Những ví dụ đó chứa một phép toán OR, trong đó cả hai bên đều có thể đúng. Điều này kết hợp với bộ định lượng của biểu thức có thể dẫn đến RẤT NHIỀU kết quả phù hợp tiềm năng tùy thuộc vào chuỗi đầu vào.

Tóm lại, kiểu TLDR:

Hãy cẩn thận cách các bộ định lượng được sử dụng kết hợp với các toán tử khác.


3
Hiện tại, câu trả lời này gần nhất với những gì tôi đang tìm kiếm: một quy tắc ngón tay cái để nhận ra một regex có thể gây ra vết nứt ngược thảm khốc.
Mike Partridge

1
Điều bạn bỏ sót, và điều dường như là một phần quan trọng của vấn đề, là thu hút các nhóm.
Mike Partridge

@MikePartridge Cũng vậy. Tôi đã cố gắng tiết chế nó nhiều nhất có thể, vì vậy có những thứ khác có thể gây ra những điều tương tự, chẳng hạn như bắt nhóm.
Jarmund

7

Tôi đã ngạc nhiên bắt gặp ReDOS một vài lần thực hiện đánh giá mã nguồn. Một điều tôi muốn khuyên bạn là sử dụng thời gian chờ với bất kỳ công cụ Biểu thức chính quy nào mà bạn đang sử dụng.

Ví dụ, trong C #, tôi có thể tạo biểu thức chính quy với một TimeSpanthuộc tính.

string pattern = @"^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$";
Regex regexTags = new Regex(pattern, RegexOptions.None, TimeSpan.FromSeconds(1.0));
try
{
    string noTags = regexTags.Replace(description, "");
    System.Console.WriteLine(noTags);
} 
catch (RegexMatchTimeoutException ex)
{
    System.Console.WriteLine("RegEx match timeout");
}

Regex này dễ bị từ chối dịch vụ và nếu không có thời gian chờ sẽ quay và ăn tài nguyên. Với thời gian chờ, nó sẽ ném mộtRegexMatchTimeoutException sau thời gian chờ nhất định và sẽ không gây ra việc sử dụng tài nguyên dẫn đến điều kiện Từ chối dịch vụ.

Bạn sẽ muốn thử nghiệm với giá trị thời gian chờ để đảm bảo nó phù hợp với việc sử dụng của bạn.


7

Phát hiện ma quỷ

  1. Hãy thử RegexStaticAnalysis của Nicolaas Weideman dự án .
  2. Hãy thử bộ dò tìm vuln-regex kiểu tập hợp của tôi có CLI cho công cụ của Weideman và các loại khác.

Quy tắc của ngón tay cái

Các regex xấu luôn do sự mơ hồ trong NFA tương ứng, bạn có thể hình dung bằng các công cụ như regexper .

Dưới đây là một số hình thức mơ hồ. Không sử dụng chúng trong regexes của bạn.

  1. Lồng các bộ định lượng như (a+)+(hay còn gọi là "chiều cao sao> 1"). Điều này có thể gây nổ theo cấp số nhân. Xem safe-regexcông cụ của ngăn phụ .
  2. Các chức năng chồng chéo được định lượng như thế nào (a|a)+. Điều này có thể gây nổ theo cấp số nhân.
  3. Tránh các Điều chỉnh chồng chéo được định lượng như \d+\d+. Điều này có thể gây ra hiện tượng thổi phồng đa thức.

Tài nguyên bổ sung

Tôi đã viết bài báo này trên regex siêu tuyến tính. Nó bao gồm vô số tài liệu tham khảo đến các nghiên cứu khác liên quan đến regex.


4

Tôi muốn nói rằng điều này liên quan đến công cụ regex đang được sử dụng. Không phải lúc nào bạn cũng có thể tránh được những loại regex này, nhưng nếu regex engine của bạn được xây dựng đúng cách thì sẽ ít có vấn đề hơn. Xem loạt blog này để biết rất nhiều thông tin về chủ đề công cụ regex.

Lưu ý cảnh báo ở cuối bài viết, trong đó backtracking là vấn đề NP-Complete. Hiện tại không có cách nào để xử lý chúng một cách hiệu quả và bạn có thể không cho phép chúng trong đầu vào của mình.


a*a*không sử dụng backreferences. Bây giờ, công cụ regex sử dụng backtracking , có lẽ, ý bạn là gì? Trong trường hợp đó, tất cả các động cơ hiện đại đều sử dụng backtracking. Bạn có thể dễ dàng vô hiệu hóa backtracking thông qua (?>...), nhưng điều đó thường xuyên hơn sẽ không thay đổi ý nghĩa của biểu thức của bạn (và trong một số trường hợp, nó có thể bị phá vỡ).
JDB vẫn nhớ Monica vào

@ Cyborgx37 rất tiếc! Ý tôi là quay lưng lại. Đã sửa.
Spencer Rathbun

Trong trường hợp đó, động cơ sử dụng backtracking hoặc không. Hầu như không có cách nào để hạn chế backtracking bằng cách hạn chế đầu vào.
JDB vẫn nhớ Monica vào

2
@JDB: "tất cả các động cơ hiện đại đều sử dụng backtracking." - Có thể điều đó đúng vào năm 2013, nhưng không còn nữa .
Kevin

@Kevin - chắc chắn. bạn thắng.
JDB vẫn nhớ Monica

3

Tôi không nghĩ rằng bạn có thể nhận ra những biểu hiện như vậy, ít nhất là không phải tất cả chúng hoặc không mà không hạn chế biểu cảm của chúng. Nếu bạn thực sự quan tâm đến ReDoSs, tôi sẽ cố gắng hộp cát chúng và kết thúc quá trình xử lý của chúng với thời gian chờ. Cũng có thể có các triển khai RegEx cho phép bạn giới hạn số lượng theo dõi ngược tối đa của chúng.


2
Tôi nghĩ bạn đang hiểu sai câu hỏi. Khi tôi đọc nó, OP thực sự đang hỏi làm thế nào anh ta có thể nhận ra một regex độc ác, chứ không phải làm thế nào anh ta có thể viết một chương trình để làm như vậy. Giống như, "Tôi đã viết bản regex này, nhưng làm thế nào tôi có thể biết liệu nó có phải là điều xấu không?"
ruakh

Uh, bạn có thể đúng. Sau đó, tôi chỉ có thể giới thiệu bài viết về việc bẻ khóa ngược thảm khốc mà @DanielHilgarth đã được liên kết trong các nhận xét.
Bergi

2
@ 0x90: Bởi vì tôi không xem xét ví dụ a*hoặc\* là "dễ bị tổn thương".
ruakh

1
@ 0x90 hoàn toàn a*không dễ bị tấn công. Trong khi đó, a{0,1000}a{0,1000}là một thảm họa regex đang chờ đợi xảy ra. Thậm chí a?a?có thể có kết quả khó chịu trong điều kiện thích hợp.
JDB vẫn nhớ Monica vào

2
@ 0x90 - Bẻ khóa ngược thảm khốc là một mối nguy hiểm bất cứ khi nào bạn có hai biểu thức trong đó một biểu thức giống hệt nhau hoặc một tập hợp con của biểu thức kia, trong đó độ dài của biểu thức có thể thay đổi và vị trí của chúng sao cho người ta có thể bỏ một hoặc nhiều ký tự cho khác thông qua backtracking. Ví dụ, a*b*c*$là an toàn, nhưng a*b*[ac]*$nguy hiểm, vì a*có thể có khả năng từ bỏ các ký tự [ac]*nếu bvắng mặt và kết quả khớp ban đầu không thành công (ví dụ aaaaaaaaaaaccccccccccd).
JDB vẫn nhớ Monica vào

0

Có một số cách mà tôi có thể nghĩ ra rằng bạn có thể thực hiện một số quy tắc đơn giản hóa bằng cách chạy chúng trên các đầu vào thử nghiệm nhỏ hoặc phân tích cấu trúc của regex.

  • (a+)+ có thể được giảm bớt bằng cách sử dụng một số loại quy tắc để thay thế các toán tử thừa thành chỉ (a+)
  • ([a-zA-Z]+)* cũng có thể được đơn giản hóa với quy tắc kết hợp dự phòng mới của chúng tôi để ([a-zA-Z]*)

Máy tính có thể chạy các bài kiểm tra bằng cách chạy các biểu thức con nhỏ của regex dựa trên các chuỗi ký tự được tạo ngẫu nhiên của các ký tự hoặc chuỗi ký tự có liên quan và xem tất cả chúng kết thúc ở nhóm nào. Đối với lần đầu tiên, máy tính giống như vậy, này là regex muốn một của, vì vậy hãy thử nó với 6aaaxaaq. Sau đó, nó thấy rằng tất cả các a và chỉ nhóm đầu tiên kết thúc trong một nhóm và kết luận rằng cho dù có đặt bao nhiêu a thì cũng không thành vấn đề, vì +tất cả đều ở trong nhóm. Cái thứ hai, giống như, này, regex muốn có một loạt các chữ cái, vì vậy hãy thử với nó -fg0uj=, và sau đó nó thấy rằng mỗi nhóm đều nằm trong một nhóm, vì vậy nó sẽ loại bỏ+ ở cuối.

Bây giờ chúng ta cần một quy tắc mới để xử lý những quy tắc tiếp theo: Quy tắc loại bỏ-không thích hợp-tùy chọn.

  • Với (a|aa)+ , máy tính sẽ xem xét nó và giống như, chúng ta thích cái thứ hai lớn đó, nhưng chúng ta có thể sử dụng cái đầu tiên đó để lấp đầy khoảng trống hơn, cho phép lấy nhiều aa nhất có thể và xem liệu chúng ta có thể lấy được gì khác không sau khi chúng tôi hoàn thành. Nó có thể chạy nó với một chuỗi kiểm tra khác, chẳng hạn như `eaaa @ a ~ aa. ' để xác định điều đó.

  • Bạn có thể tự bảo vệ mình (a|a?)+bằng cách để máy tính nhận ra rằng các chuỗi được khớp với nhau a?không phải là các chuỗi droid mà chúng ta đang tìm kiếm, bởi vì nó luôn có thể khớp ở bất kỳ đâu, chúng tôi quyết định rằng chúng tôi không thích những thứ như thế (a?)+và ném nó ra ngoài.

  • Chúng tôi bảo vệ khỏi (.*a){x}bằng cách làm cho nó nhận ra rằng các ký tự trùng khớp với nhau ađã bị.* . Sau đó, chúng tôi loại bỏ phần đó và sử dụng quy tắc khác để thay thế các bộ định lượng dư thừa trong đó (.*){x}.

Trong khi việc triển khai một hệ thống như thế này sẽ rất phức tạp, đây là một vấn đề phức tạp và có thể cần một giải pháp phức tạp. Bạn cũng nên sử dụng các kỹ thuật mà người khác đã đưa ra, chẳng hạn như chỉ cho phép regex một số tài nguyên thực thi giới hạn trước khi giết nó nếu nó không hoàn thành.


1
"thích", nhận ra thứ gì đó "muốn", "thử" đoán, "nhìn thấy" và đưa ra kết luận ("nhận ra", "xác định") là những vấn đề không hề nhỏ khó thực hiện theo thuật toán cho máy tính ... Và các ví dụ kiểm tra là không có gì để dựa vào, bạn thà cần một số loại chứng minh.
Bergi

@Bergi Ý tôi muốn nói trong các ví dụ thử nghiệm là bạn lấy một đoạn nhỏ của một regex hoàn chỉnh và chạy nó dựa trên một chuỗi thử nghiệm, như một cách đơn giản để xác định cách nó hoạt động. Tất nhiên, bạn chỉ đang thử nghiệm các khối mà bạn đã kiểm tra và đã biết, không làm những điều kỳ lạ trong các trường hợp thử nghiệm.
AJMansfield
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.