Bài 07: Hàm preg_match_all trong php

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.

1. 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.

$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).

$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"'.

$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 (.+?).

2. 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é).

$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"
    }
}

3. Lời kết

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ý.

Hãy để lại link bài viết gốc khi chia sẻ bài viết này, mình sẽ report DMCA với những website lấy nội dung mà không để nguồn hoặc copy bài với số lượng lớn.

Nguồn: freetuts.net

Profile photo of adminTheHalfHeart

TheHalfHeart

Có sở thích viết tuts nên đã từng tham gia viết ở một số diễn đàn, đến năm 2014 mới có điều kiện sáng lập ra freetuts.net. Sinh năm 90 và có 1 vợ 2 con, thích ca hát và lập trình.

ĐĂNG BÌNH LUẬN: Đăng câu hỏi trên Group Facebook để được hỗ trợ nhanh nhất.