2009-03-29 32 views
13

Tôi đang cố gắng khớp một chuỗi có thể xuất hiện trên nhiều dòng. Nó bắt đầu và kết thúc với một chuỗi cụ thể:Bao gồm các dòng mới trong hàm preg_replace của PHP

{a}some string 
can be multiple lines 
{/a} 

Tôi có thể lấy tất cả mọi thứ giữa {a}{/a} với một regex? Có vẻ như. không khớp với các dòng mới, nhưng tôi đã thử những điều sau đây mà không có may mắn:

$template = preg_replace($'/\{a\}([.\n]+)\{\/a\}/', 'X', $template, -1, $count); 
echo $count; // prints 0 

Nó phù hợp. hoặc \ n khi họ đang ở trên riêng của họ, nhưng không phải với nhau!

Trả lời

31

Sử dụng s modifier:

$template = preg_replace($'/\{a\}([.\n]+)\{\/a\}/s', 'X', $template, -1, $count); 
//            ^
echo $count; 
+0

Tuyệt vời, tôi biết nó sẽ đơn giản như thế! – DisgruntledGoat

+0

Ngoài ra, tôi chỉ thấy rằng thông tin này IS trên trang web PHP, mặc dù tôi chưa bao giờ tìm thấy nó trước khi tìm kiếm ... http://www.php.net/manual/en/reference.pcre.pattern.modifiers .php – DisgruntledGoat

3

Từ http://www.regular-expressions.info/dot.html:

"Dấu chấm phù hợp với một nhân vật duy nhất, mà không quan tâm những gì nhân vật đó là Ngoại lệ duy nhất là xuống dòng ký tự."

bạn sẽ cần thêm cờ dấu trang vào biểu thức của mình.

6

Tôi nghĩ bạn gặp nhiều vấn đề hơn chỉ là dấu chấm không khớp với dòng mới, nhưng hãy để tôi bắt đầu với đề xuất định dạng. Bạn có thể sử dụng bất kỳ ký tự dấu chấm câu nào như dấu phân cách regex, không chỉ dấu gạch chéo ('/'). Nếu bạn sử dụng một nhân vật khác, bạn sẽ không phải thoát khỏi các dấu gạch chéo trong regex. Tôi hiểu '%' là phổ biến trong số các PHP; mà có thể làm luận hình thái của bạn:

'%\{a\}([.\n]+)\{/a\}%' 

Bây giờ, lý do mà regex không làm việc như bạn dự định là vì chấm mất ý nghĩa đặc biệt của nó khi nó xuất hiện bên trong một lớp nhân vật (dấu ngoặc vuông) - vì vậy [.\n] chỉ khớp với một dấu chấm hoặc một dòng cấp. Những gì bạn đang tìm kiếm là (?:.|\n), nhưng tôi sẽ có khuyến cáo phù hợp với việc vận chuyển-lợi nhuận cũng như linefeed:

'%\{a\}((?:.|[\r\n])+)\{/a\}%' 

Đó là bởi vì từ "xuống dòng" có thể tham khảo các kiểu Unix "\ n", Kiểu "\ r \ n" kiểu Windows hoặc kiểu "Mac" cũ hơn của Mac. Bất kỳ trang web cụ thể nào cũng có thể chứa bất kỳ trang nào hoặc hỗn hợp của hai hoặc nhiều kiểu; kết hợp "\ n" và "\ r \ n" rất phổ biến. Nhưng với chế độ/s (hay còn gọi là single-line hoặc chế độ DOTALL), bạn không cần phải lo lắng về điều đó:

'%\{a\}(.+)\{/a\}%s' 

Tuy nhiên, có một vấn đề với regex ban đầu đó là vẫn còn hiện diện trong vụ việc này: các + là tham lam. Điều đó có nghĩa là, nếu có nhiều hơn một chuỗi {a}...{/a} trong văn bản, lần đầu tiên áp dụng regex của bạn, nó sẽ khớp với tất cả chúng, từ {a} đầu tiên đến số {/a} mới nhất. Cách đơn giản nhất để khắc phục điều đó là làm cho + ungreedy (aka, "lười biếng" hoặc "bất đắc dĩ") bằng cách thêm một dấu chấm hỏi:

'%\{a\}(.+?)\{/a\}%s' 

Cuối cùng, tôi không biết phải làm gì với những '$ 'trước báo giá mở đầu của đối số mẫu của bạn. Tôi không làm PHP, nhưng nó trông giống như một lỗi cú pháp đối với tôi. Nếu ai đó có thể giáo dục tôi trong vấn đề này, tôi sẽ đánh giá cao nó.

+0

Ồ, đó phải là một lỗi đánh máy - tôi đã sử dụng một biến có nguồn gốc ở đó và thay thế bằng một chuỗi cho ví dụ này. – DisgruntledGoat

+0

Đây là một lời giải thích tuyệt vời. Chúc mừng cho điều này. – craignewkirk

Các vấn đề liên quan