2013-06-22 3 views
5

Thành thật mà nói, tôi nghĩ trước tiên tôi nên yêu cầu sự giúp đỡ của bạn với cú pháp của câu hỏi này trước tiên.Làm cách nào để tạo vòng lặp với cụm từ thông dụng?

Nhưng xin vui lòng nếu bạn có thể hiểu ý tôi là chỉnh sửa tiêu đề bằng tiêu đề phù hợp.

Có cách nào để tạo mẫu có thể phân tách văn bản như thế này không.

{{START}} 
    {{START}} 
     {{START}} 
      {{START}} 
      {{END}} 
     {{END}} 
    {{END}} 
{{END}} 

Vì vậy, mọi {{START}} khớp với {{END}} của nó từ bên trong đầu tiên đến bên ngoài!

Và nếu tôi không thể làm điều đó chỉ với regex. Điều gì về việc làm nó bằng cách sử dụng PHP?

Cảm ơn bạn đã lên phía trước.

+5

Nó không thể được thực hiện với hầu hết các hương vị của regex, mặc dù có những thủ thuật, ngoài ken của tôi, mà làm cho nó có thể trong các ngôn ngữ như Perl. Đọc về bổ đề bơm để tìm hiểu lý do tại sao bạn không thể làm điều này. – siride

+0

tôi cho rằng định dạng của bạn là loại đầu vào nào đó. Nếu bạn giải thích thêm một chút có lẽ một số phương pháp thay thế có thể được đề xuất. –

+0

Có vẻ như bạn đang cố gắng phân tích cú pháp gì đó ... [Nếu có thứ gì đó gần như phức tạp như HTML (trông như vậy đối với tôi), hãy thực hiện với regexes là một ý tưởng tồi.] (Http://stackoverflow.com/câu hỏi/1732348/regex-match-open-tags-ngoại trừ-xhtml-self-contained-tags/1732454 # 1732454) – michaelb958

Trả lời

4

Điều này vượt quá khả năng của cụm từ thông dụng, chỉ có thể phân tích cú pháp ngữ pháp thông thường. Những gì bạn mô tả sẽ yêu cầu một automaton đẩy (ngôn ngữ thông thường được xác định bởi một regular automaton).

Bạn có thể sử dụng cụm từ thông dụng để phân tích các phần tử riêng lẻ, nhưng phần "chiều sâu" cần được xử lý bằng ngôn ngữ có khái niệm bộ nhớ (PHP là tốt cho việc này). Vì vậy, trong giải pháp của bạn, regexes sẽ chỉ được sử dụng để xác định các thẻ của bạn, trong khi logic thực sự để theo dõi độ sâu và xác định yếu tố thẻ END thuộc về sẽ phải là chính chương trình của bạn.

+1

PHP sử dụng công cụ regex có thể nhiều hơn là biểu thức thông thường. http://pcre.org/pcre.txt - vì vậy câu trả lời của bạn chỉ mang tính học thuật - không phải là vấn đề thực tế. Tuy nhiên bạn cũng có thể sử dụng động cơ đó để làm cách bạn phác thảo nó. Chỉ phần đầu không áp dụng cho PHP/PCRE. – hakre

1

Bạn không thể làm điều này với RegEx tinh khiết, tuy nhiên với một vòng lặp đơn giản, nó có thể được thực hiện.

JS Ví dụ:

//[.\s\S]* ensures line breaks are matched (dotall not supported in JS) 
var exp = /\{\{START\}\}([.\s\S]*)\{\{END\}\}/; 

var myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}"; 

var matches = []; 
var m = exp.exec(myString); 
while (m != null) { 
    matches.push(m[0]); 
    m = exp.exec(m[1]); 
} 

alert(matches.join("\n\n")); 

PHP (Tôi không có ý tưởng nếu điều này là đúng, nó được mãi mãi kể từ khi tôi đã làm PHP)

$pattern = "/\{\{START\}\}([.\s\S]*)\{\{END\}\}/"; 
$myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}"; 

$result = preg_match($pattern, $myString, $matches, PREG_OFFSET_CAPTURE); 
$outMatches = array(); 
while ($result) { 
    array_push($outMatches, $matches[0]); 
    $result = preg_match($pattern, $matches[1], $matches, PREG_OFFSET_CAPTURE); 
} 
print($outMatches); 

Output:

{{START}} 
test 
{{START}} 
test 2 
{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 
{{END}} 
{{END}} 

{{START}} 
test 2 
{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 
{{END}} 

{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 

{{START}} 
test4 
{{END}} 
+0

OP muốn có một giải pháp PHP. Thử lại. – michaelb958

+0

Đã thêm PHP, không biết nó có đúng hay không. Đã không thực hiện PHP trong nhiều năm. –

+0

Trong PHP regex đã đệ quy, xem http://pcre.org/ – hakre

2

Có thể! Bạn có thể có từng cấp nội dung sử dụng một biểu thức chính quy đệ quy:

$data = <<<LOD 
{{START1}} 
    aaaaa 
    {{START2}} 
     bbbbb 
     {{START3}} 
      ccccc 
      {{START4}} 
       ddddd 
      {{END4}} 
     {{END3}} 
    {{END2}} 
{{END1}} 
LOD; 

$pattern = '~(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}}))~'; 
preg_match_all ($pattern, $data, $matches); 

print_r($matches); 

giải thích:

phần: ({{START\d+}}(?>[^{]++|(?1))*{{END\d+}})

Phần này của mô hình mô tả một cấu trúc lồng nhau với {{START#}}{{END#}}

(   # open the first capturing group 
{{START\d+}} 
(?>   # open an atomic group (= backtracks forbidden) 
    [^{]++ # all that is not a { one or more times (possessive) 
    |   # OR 
    (?1)  # refer to the first capturing group itself 
)    # close the atomic group 
{END\d+}}  # 
)    # close the first capturing group 

Bây giờ vấn đề là bạn không thể nắm bắt tất cả các cấp với phần này chỉ, bởi vì tất cả các ký tự của chuỗi được tiêu thụ bởi mẫu. Nói cách khác, bạn không thể khớp các phần chồng chéo của chuỗi.

Vấn đề là để bọc tất cả phần này bên trong một sự khẳng định zero-chiều rộng mà không tiêu thụ nhân vật giống như một lookahead (?=...), kết quả:

(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}})) 

này sẽ phù hợp tất cả các cấp độ.