Hàm
preg_match
dùng để lấy kết quả theo biểu thức RegEx nhưng nó chỉ lấy đúng một kết quả duy nhất. Ví dụ bạn muốn lấy chuỗi 'freetuts' trong chuỗi 'freetuts và freetuts và freetuts' thì nó chỉ trả về đúng một giá trị 'freetuts'. Vậy để lấy hết tất cả ba chữ thì phải làm thế nào? Ta sẻ sử dụng hàm preg_match_all
.Hàm preg_match_all trong PHP
Hàm
preg_match_all
cũng có chức năng giống như preg_match
đó là so khớp và trả về kết quả của việc so khớp đó. Tuy nhiên vẫn có sự khác biệt đó là:preg_match
chỉ chỉ trả về một kết quả cho mỗi regex con.preg_match_all
sẽ trả về hết kết quả so khớp chứ không phải là kết quả đầu tiên nhưpreg_match
.
Ví dụ: lấy đoạn chuỗi bên trong cặp nháy kép của chuỗi 'xin chào "các bạn", chào mừng đến "freetuts.net"'.
Sử dụng hàm preg_match:
Trong ví dụ này có hai chuỗi nằm trong cặp nháy kép đó là chuỗi 'các bạn' và chuỗi 'freetuts.net'. Bây giờ ta sử dụng hàm
preg_match
để lấy xem kết quả thế nào.
1
2
3
4
5
| $subject = 'Hello "Everybody", welcome to "freetuts.net"' ; preg_match( '/"(.+)"/' , $subject , $matches ); echo '<pre>' ; print_r( $matches ); echo '</pre>' ; |
Kết quả sẽ là:
Array ( [0] => "Everybody", welcome to "freetuts.net" [1] => Everybody", welcome to "freetuts.net )
Mục đích của ta chỉ lấy đoạn text bên trong cặp nháy kép, nhưng nó trả về dài quá :D. Lý do là nó duyệt từ dấu nháy đầu chuỗi cho đến cuối chuỗi nên kết quả mới như vậy, đây gọi là hiện tượng Greedy mà chúng ta đã học ở bài các quy tắc Regular Expression căn bản. Vậy để lấy đoạn text trong cặp dấu nháy thứ nhất thì ta phải thêm dấu
?
đằng sâu dấu +
của chuỗi partern trên, có ý nghĩa là lấy kết quả match đầu tiên (chống greedy).
1
2
3
4
5
| $subject = 'Hello "Everybody", welcome to "freetuts.net"' ; preg_match( '/"(.+?)"/' , $subject , $matches ); echo '<pre>' ; print_r( $matches ); echo '</pre>' ; |
Kết quả sẽ là:
Array ( [0] => "Everybody" [1] => Everybody )
Sử dụng hàm preg_match_all:
Như vậy các bạn thấy
preg_match
chỉ lấy được một kết quả duy nhất. Có cách nào lấy hết kết quả không? Để trả lời ta tìm hiểu hàm preg_match_all
nhé.- Cú pháp:
preg_match_all ($pattern, $subject, &$matches)
- Trong đó:
$partern
là biểu thức Regular Expression$subject
là chuỗi muốn kiểm tra&$matches
là biến lưu kết quả sau khi match
Như ở ví dụ trên, tức là lấy tất cả các chuỗi bên trong cặp nháy kép của chuỗi 'xin chào "các bạn", chào mừng đến "freetuts.net"'.
1
2
3
4
5
| $subject = 'Hello "Everybody", welcome to "freetuts.net"' ; preg_match_all( '/"(.+?)"/' , $subject , $matches ); echo '<pre>' ; print_r( $matches ); echo '</pre>' ; |
Kết quả là :
Array ( [0] => Array ( [0] => "Everybody" [1] => "freetuts.net" ) [1] => Array ( [0] => Everybody [1] => freetuts.net ) )
Kết quả nó trả về một mảng gồm 2 phần tử và giá trị của mỗi phần tử giống như hàm kết quả của hàm
preg_match
nên mình không giải thích thêm về phần này nhé.
Giờ bạn thay đổi chuỗi
$subject = 'Hello "Everybody", welcome to "freetuts.net", thanks for "like it"'
. Bạn chạy và kết quả sẽ là:Array ( [0] => Array ( [0] => "Everybody" [1] => "freetuts.net" [2] => "like it" ) [1] => Array ( [0] => Everybody [1] => freetuts.net [2] => like it ) )
Rất đơn giản đúng không nào. Bây giờ lấy kết quả thì có 2 lựa chọn:
- Nếu lấy có dấu ngoặc thì chọn phần tử thứ nhất
- Nếu lấy không có dấu ngoặc thì chọn phần tử thứ 2
Giải thích tại sao lại có 2 phần tử thì như bài trước, phần tử thứ nhất là toàn chuỗi toàn partern, phần tử thứ 2 là kết quả của đoạn RegEx
(.+?)
.Ví dụ hàm preg_match_all trong PHP
Mình sẽ đưa ra một ví dụ để các bạn thực hành như sau: Lấy tất cả nội dung bên trong tất cả thẻ
div
của một file html.
Ta có hai vấn đề cần quan tâm:
- Để lấy tất cả các đoạn text trong tất cả thẻ div thì ta phải dùng đến hàm
preg_match_all
trong php. - Đoạn
$pattern
sẽ có dạng$pattern = '/<div>(.*?)<\/div>/'
. Lưu ý phải có dấu ? nha bạn, vì có dấu ? thì máy sẽ hiểu là lấy từng kết quả chứ không phải duyệt hết chuỗi rồi lấy (gọi là Greedy, bạn quay lại bài trước để xem phần này nhé).
1
2
3
4
5
| $subject = '<div>Div1</div><div>Div2</div><div>Div3</div>' ; preg_match_all( '/<div>(.*?)<\/div>/' , $subject , $matches ); echo '<pre>' ; var_dump( $matches ); echo '</pre>' ; |
Kết quả sẽ là:
array(2) { [0]=> array(3) { [0]=> string(15) "Div1" [1]=> string(15) "Div2" [2]=> string(15) "Div3" } [1]=> array(3) { [0]=> string(4) "Div1" [1]=> string(4) "Div2" [2]=> string(4) "Div3" } }
Kết luận
Như vậy để lấy tất cả kết quả thì ta sử dụng hàm preg_match_all còn chỉ lấy một kết quả đầu tiên thì ta sử dụng hàm preg_match. Thực tế thì bạn sử dụng hàm preg_match_all để thay thế cho hàm preg_match cũng được bằng cách lấy phần tử đầu tiên, tuy nhiên cách này rất rườm rà nên tùy vào trường hợp mà sử dụng cho hợp lý.
Blog tổng hợp những kinh nghiệm được học, áp dụng và chia sẻ