Thao tác dữ liệu ngày tháng năm sinh trong bảng họ tên bằng PHP

Ngày tháng năm sinh là dữ liệu rất thú vị để thống kê các thay đổi về họ tên người, chẳng hạn như khuynh hướng tên có nhiều từ hơn, giảm đệm Văn, Thị, các tên mới xuất hiện, các tên dần kém phổ biến, vân vân.

Cũng tương tự với họ tên, chúng ta cũng cần chuẩn hóa dữ liệu ngày tháng năm sinh.

Người Việt Nam thường sử dụng cấu trúc viết ngày trước, rồi đến tháng và cuối cùng là năm sinh.

Để phân tách giữa ngày tháng năm người ta dùng ký tự /

Ví dụ 15/6/1995.

Ở đây có thể có hai cách viết đối với ngày, tháng cho các giá trị dưới 10. Có thể có số 0 đằng trước. Ví dụ 03/05/1995 hoặc không có số 0, ví dụ 3/5/1995. Chúng ta cần thống nhất kiểu định dạng.

Cá nhân tôi thích chọn kiểu 3/5/1995 hơn, vì tách dữ liệu sẽ dễ hơn.

Các biến thể

  • Sử dụng dấu phân cách ngày tháng năm khác / ví dụ 3-5-1995, 3 – 5 – 1995 hoặc 3.5.1995
  • Thứ tự ngày tháng năm bị đảo lộn. Ví dụ để năm/tháng/ngày 1995/5/3 hoặc tháng/ngày/năm (văn hóa phương Tây hay dùng);

Các thuộc tính cần kiểm tra

  • Kiểm tra không có dữ liệu: tức là cột ngày tháng năm sinh không có dữ liệu

Ta có thể dùng hàm If rồi so sánh dữ liệu với NULL và rỗng, ví dụ:

if (($ngay_sinh==NULL) || ($ngay_sinh=='')) {echo "không có dữ liệu";}
  • Thay thế – hoặc . bằng ký tự tiêu chuẩn mà chúng ta chọn là /

Ta có thể dùng hàm str_replace để thực hiện nhiệm vụ này, ví dụ:

$ngay_sinh1 = "3-5-1995";
$ngay_sinh2 = "3.5.1995";

$thaythe =  array('-', '.');
$ngay_sinh1 =   str_replace($thaythe, "/", $ngay_sinh1);
$ngay_sinh2 =   str_replace($thaythe, "/", $ngay_sinh2);

echo $ngay_sinh1; // kết quả 3/5/1995
echo "</br>";
echo $ngay_sinh2; // kết quả 3/5/1995
  • Kiểm tra sai dữ liệu: tức là có các ký tự không thể có trong cấu trúc dữ liệu ngày tháng năm thông thường, ví 5/7,/1987 có ký tự , hoăc 5/7a/1987 có ký tự a

Dữ liệu ngày tháng năm sau khi sử dụng / để ngăn cách ngày tháng năm sẽ chỉ bao gồm số và dấu /

Chúng ta sẽ dùng hàm để kiểm tra xem một dữ liệu nào đó có ký tự không chuẩn nào không bằng lệnh sau:

preg_match('/[a-z]/', '5/7b/1987', $matches1);

if (count($matches1) > 0) {echo "có lỗi 1";}

echo "</br>";

$ngaythang='5/7,/1987';
$kytuloi = array('?',')', '(', '[', ']', '{', '}', '.', ',', '"', ':', ';', '~', '!', '@', '#', '%', '^', '&', '*', '+', '=', '-', '_', '>', '<'); //
$t = count($kytuloi);
$loi=array();
 for ($i=0;$i<$t;$i++) {
     $l=mb_strpos($ngaythang,$kytuloi[$i]);
     if ($l>0) {$loi[$i]=1;}
 }
if (count($loi) > 0) {echo 'có lỗi 2';} 

Sai dữ liệu cũng có thể là thiếu một trong các dữ liệu ngày, tháng, năm (tức là chỉ có 2 trên 3 dữ liệu tiêu chuẩn).

Để kiểm tra nhanh cái này chúng ta sẽ đếm xem có bao nhiêu dấu /, nó phải có đúng 2 dấu / mới đúng tiêu chuẩn. Mã

$gach=substr_count('6/1987', '/');
if ($gach!=2) {echo 'có lỗi';} // $gach = 1, do vậy đây là thông tin ngày tháng năm lỗi
  • Kiểm tra cấu trúc ngày/tháng/năm có được tuân thủ.

Dữ liệu ở bước này trước khi đi vào kiểm tra cần vượt qua bài test dữ liệu lỗi ở mấy bước trên để chắc chắn nó có cấu trúc số/số/số

Vì ngày đứng trước giá trị của nó chỉ được phép nằm trong khoảng từ 1 – 31;

Tháng ở giữa chỉ được phép nằm trong khoảng 1 – 12;

Năm thì tùy dữ liệu của bạn. Đối với người sống thì nó không được nhỏ hơn 1900 và lớn hơn 2022 (năm hiện tại viết bài này là 2021).

Đoạn mã sẽ giải quyết và thay thế được các mã dài dòng ở trên đó là thông qua regular expression (được nhiều ngôn ngữ lập trình hỗ trợ chứ không riêng gì PHP, đây là giải pháp rất mạnh, nhanh gọn để xử lý chuỗi).

$nt1="5/7/1987";
$nt2="o5/7/1987"; // có chữ o
$nt3="7/1987"; // chỉ có tháng và năm
$nt4="7/5"; // chỉ có ngày và tháng
$nt5="1987/7/5"; // năm lộn lên đầu

preg_match('/\b\d{1,2}\/\d{1,2}\/\d{4}\b/', $nt1, $matches1);
if (count($matches1) == 0 || count($matches1) == NULL) {echo "có lỗi";} else { echo "không có lỗi";} // Kết quả không có lỗi

echo "</br>";

preg_match('/\b\d{1,2}\/\d{1,2}\/\d{4}\b/', $nt2, $matches2);
if (count($matches2) == 0 || count($matches2) == NULL) {echo "có lỗi";} else { echo "không có lỗi";} // kết quả có lỗi

echo "</br>";

preg_match('/\b\d{1,2}\/\d{1,2}\/\d{4}\b/', $nt3, $matches3);
if (count($matches3) == 0 || count($matches3) == NULL) {echo "có lỗi";} else { echo "không có lỗi";} // kết quả có lỗi

echo "</br>";

preg_match('/\b\d{1,2}\/\d{1,2}\/\d{4}\b/', $nt4, $matches4);
if (count($matches4) == 0 || count($matches4) == NULL) {echo "có lỗi";} else { echo "không có lỗi";} // kết quả có lỗi

echo "</br>";

preg_match('/\b\d{1,2}\/\d{1,2}\/\d{4}\b/', $nt5, $matches5);
if (count($matches5) == 0 || count($matches5) == NULL) {echo "có lỗi";} else { echo "không có lỗi";} // kết quả có lỗi

Câu lệnh preg_match('/\b\d{1,2}\/\d{1,2}\/\d{4}\b/', $ngaythang, $matches) sẽ kiểm tra dữ liệu ngày tháng năm và bất cứ dữ liệu nào khác cấu trúc ngày (1 hoặc 2 số)/tháng (1 hoặc 2 số)/năm (phải 4 số) thì đều báo lỗi.

Tuy nhiên nó vẫn chưa phát hiện được khoảng hợp lệ của ngày (1 – 31), tháng (1 – 12). Chúng ta vẫn cần xử lý vấn đề này.

Câu lệnh để phát hiện điều này (giả dụ thêm là dữ liệu của tôi cần năm hợp lý nằm trong khoảng 2004 đến 2016):

$ngaythang = '05/07/2015';
$tach_ngaythang=array();
$tach_ngaythang=explode('/', $ngaythang); // cho vào mảng

$ng=$tach_ngaythang[0]; 
$th=$tach_ngaythang[1];
$na=$tach_ngaythang[2];

$ngs = (int)$ng; // chuyển thành dạng số
$ths = (int)$th;
$nas = (int)$na;

if ($ngs < 1 || $ngs > 31 || $ths < 1 || $ths > 12 || $nas > 2016 || $nas < 2004) 
             {echo "có lỗi khoảng giá trị được phép";} 
        else 
             {echo "dữ liệu hợp lệ: "; $ngay_chuan=$ngs.'/'.$ths.'/'.$nas; echo $ngay_chuan;}

Leave a Comment