Đầu tiên, phân tích cú pháp biểu thức và xây dựng một cây phản ánh cấu trúc cú pháp của cụm từ thông dụng và bao gồm nút đầu cuối xuất hiện một cách hợp lý ở cuối. Ví dụ: trong ký hiệu lisp, ví dụ của bạn có thể trông giống như sau:
(concat
(repeat 2
(concat
(charset
(range a z)
(range A Z))
(literal _)
(charset
(range 0 9))))
terminator)
Tiếp theo, tạo chủ đề để bạn có thể sử dụng đệ quy để tạo mở rộng tổ hợp. Bằng cách đó, tôi có nghĩa là ví dụ các nút a..z
trong (concat a .. z)
tất cả cần phải có con trỏ từ điểm này đến điểm tiếp theo, vì vậy a
trỏ đến b
, v.v. và chính nút concat
trỏ đến người kế nhiệm của nó. Ý tưởng là bạn có thể tạo ra một phiên bản của phần tử hiện tại trong phần mở rộng, và recurse vào phần tử tiếp theo, và khi phần tử tiếp theo trả về, bạn có thể thử phiên bản tiếp theo của phần tử hiện tại, v.v. bạn quay trở lại người gọi của bạn (người tiền nhiệm hoặc cha mẹ). Luồng này được thực hiện dễ dàng nhất với một chồng và một sự di chuyển sau của cây. Nếu bạn cẩn thận đẩy các nút trong quá trình truyền tải thứ tự sau, phần đầu của ngăn xếp sẽ là phần tử tiếp theo theo thứ tự.
(Một thay thế cho luồng là cấu trúc cây để các phần tử tiếp theo trong mỗi concat
nút là con của nút trước đó, và trẻ em repeat
nút điểm trở lại nút lặp lại.)
Sau đó viết một thường trình (hoặc tập hợp các thói quen sử dụng đối sánh mẫu hoặc các phương thức ảo nếu các nút trong cây được thực hiện bằng cách sử dụng đa hình trong một ngôn ngữ hướng đối tượng), cho bất kỳ loại nút nào, tạo ra đầu ra chính xác và đệ quy vào nút tiếp theo hoặc trẻ em theo cách thích hợp. Ví dụ, trong giả:
if node is of form (repeat n): # non-variable repeat
for i in 1 to n
recurse into child
recurse into threaded successor
if node is of form (concat ...):
recurse into first element # last element will recurse into successor
if node is of form (literal x):
emit x
recurse into successor
remove x
if node is of form (charset ...):
for each element in charset:
emit element
recurse into successor
remove element
if node is terminator:
add string created thus far to final output list
vv Như bạn có thể quan sát, con của một nút repeat phải không recurse vào sự kế thừa của nút repeat
, vì vậy mà cần phải được tính đến khi luồng cây. Sự chăm sóc tương tự cần được thực hiện là "tiến độ hiện tại" không bị mất khi đến cuối các nút con của nút repeat
; Ngoài ra, sự kế thừa của các nút con có thể trỏ tới chính nút lặp lại (tức là một đóng cửa thực sự trên biểu đồ các nút), nhưng điều đó sẽ yêu cầu lưu trữ một bộ đếm ở đâu đó.
Tất cả trong tất cả, việc hoàn thành việc này có thể mất vài ngày, tùy thuộc vào mức độ linh hoạt và hiệu suất cần thiết. Cũng lưu ý rằng một số cấu trúc nhất định, chẳng hạn như sao Kleene hoặc đóng (*
hoặc +
trong regex mở rộng) sẽ dẫn đến danh sách vô hạn. Ngôn ngữ hỗ trợ trình tạo (ví dụ: cú pháp lặp của C#) hoặc coroutines/continuations (ví dụ: Gọi/cc) hoặc đánh giá lười (ví dụ: Haskell) có thể cho phép lặp qua vài phần tử đầu tiên của danh sách mà không phải đánh giá toàn bộ danh sách. Ngoài ra, việc chọn đầu ra tiềm năng ngẫu nhiên thay vì lặp lại toàn diện có thể thích hợp hơn để cung cấp các ví dụ tương ứng với cụm từ thông dụng.
Đó là 5200 kết quả phù hợp. Chắc chắn bạn muốn có nó? Và xin lỗi, tôi không thể làm python hay perl. – Dykam
Tôi cũng rất thận trọng. Số lượng các kết hợp có thể phát triển theo cấp số nhân so với chiều dài regex, do đó, bất cứ điều gì, nhưng chuỗi ngắn có thể được ** rất ** thời gian và tiêu thụ bộ nhớ. – Agos
@etotheipi: thay vì giải thích giải pháp được giải quyết của bạn cho vấn đề, thay vào đó hãy cho chúng tôi biết bạn đang thực sự muốn đạt được điều gì ... –