Sử dụng Regular Expression

Sử dụng regular expression để tìm kiếm, tách lọc dữ liệu theo mẫu chỉ định. Không biết regular expression là một thiếu sót lớn của developer.


Sử dụng Regular Expression

Regular expression là gì

Mỗi regular expression là 1 pattern dùng để so khớp trong chuỗi. Biết sử dụng regular expression sẽ rất có lợi vì nó giúp giải quyết các bài toán tìm kiếm, so khớp, bóc tách các chuỗi một cách nhanh chóng, gọn gàng.

Pattern regular trong php

Trong php, bạn khai báo pattern ở trong các dấu /, # , ~ }. Những dấu này gọi là delimiter. Sau đây là ví dụ khai báo vài pattern:

/abc/
#[0-9]{3}$#
+php+
%[a-zA-Z0-9_-]%

Nếu cần diễn tả ký tự delimiter thì trong pattern thêm dấu \  vào trước nó hoặc dùng delimiter khác. Ví dụ sau là 2 cách diễn tả pattern http://

/http:\/\//
#http://#

Các hàm php xử lý regular expression

Trong php có một vài hàm giúp bạn sử dụng regular expression:

Hàm preg_match

Hàm này có hai tham số là $pattern$string.  Nó trả về 1 giá trị true/false cho biết $pattern có được tìm thấy trong chuỗi hay không. Mời xem ví dụ:

<?php
  $kq1 = preg_match('/thân/', "Mẹ tôi hai tiếng thân thương"); //true
  $kq2 = preg_match('/yêu/', "Mẹ tôi hai tiếng thân thương"); //false
  $kq3 = preg_match('/ng$/', "Mẹ tôi hai tiếng thân thương"); //true
  $kq4 = preg_match('/^Má/', "Mẹ tôi hai tiếng thân thương"); //false
  if ($kq1) echo "Tìm thấy chữ thân<br>";   
  else echo "Không tìm thấy chữ thân<br>";

  if ($kq2) echo "Tìm thấy chữ yêu<br>"; 
  else echo "Không tìm thấy chữ yêu<br>";

  if ($kq3) echo "Tận cùng là ng<br>";
  if ($kq4) echo "Bắt đầu là Má<br>";
?>

Kết quả:

Tìm thấy chữ thân
Không tìm thấy chữ yêu
Tận cùng là ng

Hàm preg_replace

Sử dụng regular expression để tìm và thay thế là rất hay, đây là công dụng của hàm preg_replace() . Nó giúp tìm 1 pattern và rồi thay thế bởi chuỗi hoặc pattern mới. Mời xem ví dụ:

<?php
 $str ="
    Vân Tiên nghe nói động lòng,
    Đáp rằng: Ta đã trừ dòng lâu la.
    Khoan khoan ngồi đó chớ ra,
    Nàng là phận gái, ta là phận trai.
    Tiểu thư con gái nhà ai,
    Đi đâu nên nỗi mang tai bất kỳ";
   $str = preg_replace('/(ai)|(òng)/', "...", $str);
   echo "<pre>",$str;
?>

Kết quả:

    Vân Tiên nghe nói động l...,
    Đáp rằng: Ta đã trừ d... lâu la.
    Khoan khoan ngồi đó chớ ra,
    Nàng là phận gái, ta là phận tr....
    Tiểu thư con gái nhà ...,
    Đi đâu nên nỗi mang t... bất kỳ

Hàm preg_split

Sử dụng regular expression để tách dữ liệu theo mẫu cũng rất là hay luôn. Đây là tác dụng của hàm preg_split(). Hàm này tách chuỗi theo mẫu mà bạn chỉ định thành mảng. Ví dụ:

<?php
$string = 'Mồi phú quí dữ làng xa mã, Bả vinh hoa lừa gã công khanh; Giấc Nam Kha khéo bất bình. Bừng con mắt dậy thấy mình tay không';
$pattern = '/[,;.]/';
$arr = preg_split( $pattern, $string); print_r($arr);
echo "<br>",implode(" - ", $arr);
?>

Kết quả:

Array (
[0] => Mồi phú quí dữ làng xa mã
[1] => Bả vinh hoa lừa gã công khanh
[2] => Giấc Nam Kha khéo bất bình
[3] => Bừng con mắt dậy thấy mình tay không )
Mồi phú quí dữ làng xa mã - Bả vinh hoa lừa gã công khanh - Giấc Nam Kha khéo bất bình - Bừng con mắt dậy thấy mình tay không

Dấu chấm trong pattern

Trong pattern, dấu . dùng để diễn tả 1 ký tự bất kỳ nào đó, ngoại trừ ký tự newline

Pattern ở đầu và cuối chuỗi

Dấu ^ trong pattern dùng để diễn tả vị trí đầu của chuỗi hoặc đầu của dòng. Chẳng hạn với giá trị $s=‘abc’, thì pattern /^a/ là khớp còn /^b/ thì không khớp .

Dấu $ trong pattern dùng để diễn tả vị trí cuối chuỗi hoặc cuối dòng. Chẳng hạn với $s=’abc’ thì pattern  /c$/ sẽ khớp còn /a$/ thì không khớp.

Class trong pattern

Class trong pattern được bao bởi dấu [ ] , ví dụ [ps] là một class. Mỗi class được dùng để diễn tả 1 ký tự. Có nghĩa là khớp nếu có 1 ký tự  trong chuỗi khớp với 1 trong những ký tự của class.  

Ví dụ để so khớp ký tự u hoặc o, thì diễn tả bằng class [ai].  Như vậy /th[ai]nh/ sẽ khớp với  chuỗi thanh hoặc thinh.

Trong class, dấu – để diễn tả một vùng liên tục. Ví dụ [0-6]  diễn tả một digit từ 0 đến 6.  Còn nếu đặt dấu ^ ở ngay sau [ trong class thì sẽ phủ định class đó. Nghĩa là sẽ so khớp với mọi ký tự không nằm trong class. Ví dụ  a[^m]  nghĩa là “a theo sau bởi 1 ký tự không phải m”. Vì vậy sẽ không khớp trong chuỗi Tam mà khớp với chuỗi Tai

Chú ý:

  • Khi diễn tả class thì thứ tự các ký tự trong class là không quan trọng. Ví dụ 2 class sau là giống hệt nhau: [ps] [sp]
  • ^  sẽ mang nghĩa thường nếu không đặt nó ngay sau [ . Ví dụ  [x^]  sẽ khớp với x hoặc ^.
  • ] sẽ mang nghĩa thường nếu đặt nó ở ngay sau [  hoặc  [^ . Ví dụ  []x] sẽ khớp với ] hoặc x.  [^]x] sẽ khớp với bất kỳ ký tự nào không phải là ] hoặc x.
  • –  sẽ mang nghĩa thường nếu đặt nó ở ngay sau [ hoặc [^  hoặc ngay trước ]. Ví dụ  [-x] và [x-] đều so khớp với – hoặc x.

Viết tắt trong regular expression

  • \d là viết tắt của [0-9]
  • \w  để để diễn tả 1 từ
  • \s để để diễn tả 1 “khoảng trắng” tạo bởi space hoặc tab

Ví dụ \s\d diễn tả một ký tự trắng theo sau là một digit. [\s\d] khớp với ký tự trắng hoặc một digit.

Lặp lại class trong regular expression

Dấu ? * +  được dùng khi muốn lặp lại class. Dấu + để diễn tả sự lặp lại từ 1 trở lên, * để diễn tả sự lặp lại từ 0 trở lên, còn ? là để diễn tả 1 ký tự. Ví dụ:

<?php
$str ="Tèo: 0918667788; Tý: 012777345; Lượm: 86927322";
$pattern="/[0-9]+/";
preg_match($pattern, $str, $arr); var_export($arr); echo "<br>";
preg_match_all($pattern, $str, $arr); var_export($arr);
?>

Kết quả:

[0 => 0918667788]
[0 => [0 => 0918667788, 1 => 012375345, 2 => 86927302 ] ]

Back reference trong regular expression

Back reference được đặt bên ngoài class, back reference gồm dấu \ và 1 digit >0. Mỗi back reference tương ứng với 1 capturing subpattern trước đó. 

Một số ví dụ sử dụng regular expression

Tìm chuỗi con trong chuỗi mẹ

<?php //regex1.php
    $str = 'Anh thương em Anh đi đâu đâu';
    $regex = '/a[a-z][a-z] /';
    if (preg_match($regex, $str) ==true) echo "Tìm thấy" ; 
    else echo "Không thấy";
?> 
<hr>
<?php //không phân biệt hoa thường
    $regex = '/a[a-z][a-z] /i'; 
    if (preg_match($regex, $str) ==true) echo "Tìm thấy" ; 
    else echo "Không thấy";
?> 

Tách chuỗi thành mảng

<pre>
<?php //regex2.php
$string = 'Mồi phú quí dữ làng xa mã
Bả vinh hoa lừa gã công khanh
Giấc Nam Kha khéo bất bình
Bừng con mắt dậy thấy mình tay không';
$pattern = '/\r\n/';
$arr = preg_split( $pattern , $string);
var_export( $arr );
?>

Tìm chuỗi unicode dùng regular expression

Khi cần tìm chuỗi con unicocde, dùng chị thị /u ở sau pattern. Mỗi ký tự unicode diễn tả bằng \pL , số thì dùng \N

Tìm chuỗi con thõa điều kiện: sau l/v là 1 ký tự unicode, sau ký tự unicode là khoảng trắng </h3>
<pre>
<?php
echo $str = 'Vạn lý thanh giang vạn lý thiên.
Nhất thôn tang giá, nhất thôn yên.
Ngư ông thuỵ trước vô nhân hoán.
Quá ngọ tỉnh lai tuyết mãn thuyền. ';
?></pre>
<?php
$pat = '/[lv]\pL\s/u';  
preg_match_all($pat, $str, $kq) ;//kết quả tìm trong tham số thứ 3 là $kq
var_export($kq);
?>
Tìm các chữ ng, sau đó là 1 hoặc nhiều ký tự unicode, sau nữa là khoảng trắng, không phân biệt hoa thường
<pre><?php
$str = 'Bóng gương thấp thoáng dưới mành
Cỏ cây cũng muốn nổi tình mây mưa
Chìm đáy nước cá lờ đờ lặn
Lửng da trời nhạn ngẩn ngơ sa
Hương trời đắm nguyệt say hoa
Tây Thi mất vía, Hằng Nga giật mình';
$pat = '/ng\pL+\s/iu';
preg_match_all($pat, $str, $arr); //các chuỗi tìm được trong $arr
var_export($arr);
?>

Tìm và thay thế với regular expression 

<?php
$pat = '/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/';
$replace = '\4/\3/\1\2';
$str = 'Hôm nay là ngày: <b>2023-9-27</b>';
echo preg_replace($pat, $replace, $str); 
?>
<?php
$str = 'Nguyễn     Văn     Tèo';
$str = preg_replace('/\s\s+/', ' ', $str);
echo $str; //Nguyễn Văn Tèo
?>
<?php
$str = 'Nguyễn   @   Văn  !  Tèo ';
$str = preg_replace('/[\s@!]/', ' ', $str, -1, $count);
echo $str , " , ", $count; //Nguyễn Văn Tèo , 13
?>

Tìm các số trong chuỗi dùng regular expression

<?php
$str = "Ngày sinh: 15/04/1990";
$pat = '/\d+/';
preg_match($pat, $str, $m );
var_export( $m ); // [0 => 15 ]
?>
<?php
$subject = "Ngày sinh: 15/04/1990";  $pattern = '/\d+/';
preg_match_all($pattern, $subject, $matches ,PREG_SET_ORDER);
?>
<?php var_export($matches);?> <hr>
<?php echo $matches[2][0],"-", $matches[1][0],"-",$matches[0][0]; ?>

Kiểm tra dạng thức email của một chuỗi dùng regular expression

<?php 
$regexMail = '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/';
$m = "abc123@lolhaha";  
if ( preg_match($regexMail, $m)==true) echo "$m là địa chỉ hợp lệ";
else echo "$m là địa chỉ không hợp lệ";
?>
<?php 
$regexMail = '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/';
$m = "teonv@abc.com";
if (preg_match($regexMail, $m)==true) echo "$m là địa chỉ hợp lệ";
else echo "$m là địa chỉ không hợp lệ";
?>
<?php 
$m = "teonguyen.123@vbu.edu.vn";
$regex='/^[^\W][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*\@[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*\.[a-zA-Z]{2,4}$/';
if (preg_match($regex, $m)) echo "$m là địa chỉ hợp lệ";
else echo "$m là địa chỉ không hợp lệ";
?>

Sử dụng regular expression để kiểm tra một chuỗi có phải là địa chỉ ip hay không

<?php
$ip = "255.255.255.255";
$regex= '/^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:[.](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/';
if (preg_match($regex,$ip)) echo "Địa chỉ $ip là hợp lệ";
else "Địa chỉ $ip không hợp lệ"; ?>

Kiểm tra một chuỗi có khớp với dịnh dạng số điện thoại hay không

<?php
$phone = "(232) 555-5555";
$regex='/^\(?[0-9]{3}\)?|[0-9]{3}[-. ]? [0-9]{3}[-. ]?[0-9]{4}$/';
if (preg_match($regex, $phone)) echo "Số $phone hợp lệ";
else echo "Số $phone không hợp lệ";
?>

Mời xem các trang liên quan :