Categories PHP-MySQL

Các câu lệnh php dùng để thống kê họ tên

Thống kê họ tên có mấy nhiệm vụ cơ bản sau:

  • Phân loại theo giới tính: hiện nay vẫn chủ yếu là nam và nữ;
  • Thống kê họ phổ biến: ví dụ Nguyễn, Trần, Lê;
  • Thống kê tên phổ biến: trong 2 giới nam và nữ;
  • Thống kê các đệm phổ biến: trong 2 giới nam và nữ;
  • Thống kê các đệm đặc biệt như Văn trong nam, và Thị trong nữ;
  • Thống kê số từ trung bình trong tên / phân loại theo giới tính;
  • Thống kê số ký tự trung bình trong tên / phân loại theo giới tính;
  • Nếu có năm sinh có thể thống kê khuynh hướng thay đổi theo thời gian, sử dụng phân nhóm theo năm, và dùng các thuộc tính trên, chẳng hạn đệm Thị và Văn có chiều hướng giảm không. Họ tên nhiều từ có khuynh hướng tăng không. Tên phổ biến thay đổi thế nào qua từng năm;

Các câu lệnh PHP

  1. Phân loại giới tính

Để phân loại giới tính được chính xác, chúng ta cần chuẩn hóa bảng dữ liệu liên quan đến giới.

Có thể dùng hàm chuan_hoa_hotenchuyen_ma_hoa trong bài viết này để đưa dữ liệu về dạng thống nhất, nó sẽ chuyển thông tin giới về dạng ký tự thường, loại bỏ khoảng trắng, ký tự dư thừa, đồng bộ mã hóa UTF-8.

Tuy nhiên dùng hàm chuyen_ma_hoa để mã hóa lại 2 dữ liệu mà ta biết rõ là nam và nữ là quá dư thừa. Vì trong các ký tự chỉ có ữ là có 2 biến thể mã hóa. Do vậy ta có thể viết lại hàm để câu lệnh nhanh gọn hơn:

function ma_hoa_gioi($str) {    

$phothong='ữ';
$itdung='ữ';

    $str = str_replace($itdung, $phothong, $str);

return $str;
}

Nếu dữ liệu của bạn lớn, và gặp giới hạn kiểu như:

Maximum execution time of 120 seconds exceeded

Bạn có thể sửa bằng cách thêm đoạn mã sau vào file php để gia tăng thời gian thực thi câu lệnh:

set_time_limit(500); // tăng thời gian thực thi

Tiếp theo chúng ta cần xác định dữ liệu lỗi, tức là tìm các trường dữ liệu mà giới khác nam và nữ, ví dụ n hoặc NULL, rỗng dữ liệu.

Trong MySQL để thống kê nhanh các dạng dữ liệu trùng nhau (ý ở đây là chúng ta muốn biết có bao nhiêu trường nam và nữ), bạn làm như sau:

  • Tại bảng dữ liệu cần thống kê bạn click vào SQL (thanh phía trên, cạnh Structure);
  • Tiếp đến bạn thêm câu lệnh dưới đây, rồi nhấn Go:
SELECT * , COUNT(*) AS number_record
FROM ten_bang_du_lieu
GROUP BY ten_cot_du_lieu
HAVING number_record > 1

Ví dụ, bảng của tôi tên là hoten, và cột dữ liệu cần thống kê là gioi thì câu lệnh cụ thể sẽ như thế này:

SELECT * , COUNT(*) AS number_record
FROM hoten
GROUP BY gioi
HAVING number_record > 1

Nếu muốn lôi cả các trường chỉ có một bản ghi, bạn chuyển mã thành number_record > 0.

Thường số lượng dữ liệu sai sót với trường giới rất thấp. Kết quả của tôi cho thấy, chỉ có 8 hàng nhập liệu sai trên tổng số hơn 240 ngàn hàng dữ liệu.

Các dữ liệu sai nên được đánh dấu (đừng xóa, vì có thể cần xem lại) để lúc viết lệnh data này không đưa vào thống kê.

Câu lệnh PHP để lọc giới tính rất đơn giản, bạn chỉ việc dùng hàm if:

if ($gioi=="nam") {câu lệnh PHP;}
if ($gioi=="nữ") {câu lệnh PHP;}

Bạn cũng có thể mã hóa nữ là 0, nam là 1 để việc thao tác dữ liệu đơn giản hơn. Lúc này cột giới sẽ chỉ gồm dữ liệu số là 0 và 1. Trường dữ liệu sai có thể để là 2.

2. Thống kê họ

Trước khi thống kê họ, họ tên phải được chuẩn hóa trước bằng hai hàm nói ở trên.

Sau đó chúng ta dùng hàm explode(' ', $str) để tách các từ theo dấu cách trắng (white-space), kết quả sẽ trả về một mảng, mà các phần tử của nó lần lượt là các từ trong tên. Câu lệnh:

$str = "nguyễn đức anh";
$tach_hoten = explode(' ', $str);

echo $tach_hoten[0]."</br>"; // cho kết quả là nguyễn

echo $tach_hoten[1]."</br>"; // cho kết quả là đức

echo $tach_hoten[2]; // cho kết quả là anh

Phần tử đầu tiên của mảng chính là họ. Trong ví dụ với tên biến trên thì đó là $tach_hoten[0]

Ngoài ra, chúng ta có thể sử dụng câu lệnh preg_split để cho kết quả tương tự, ví dụ:

$str = "nguyễn đức anh";
$tach_hoten = preg_split('/\s+/', $str);;

print_r($tach_hoten);

// Kết quả: Array ( [0] => nguyễn [1] => đức [2] => anh )

Với thống kê họ không cần phân theo giới tính, kết quả chung toàn bộ dữ liệu quan trọng hơn. Tất nhiên bạn có thể phân theo giới nếu muốn.

3. Thống kê tên

Sau khi tách họ tên vào mảng, nếu phần tử đầu tiên là họ, thì phần tử cuối cùng sẽ là tên. Theo cách xưng hô thông thường của người Việt Nam thì trừ những người tên Anh trùng với đại từ nhân xưng được gọi kèm đệm (ví dụ Vân Anh, Lan Anh, Đức Anh), còn lại thì thường chỉ gọi bằng tên là từ cuối cùng trong họ tên (ví dụ Tuấn, Hà, Dung, Minh).

Để làm điều này trước hết cần xác định số phần tử của mảng bằng câu lệnh:

$n = count($tach_hoten);

Tên sẽ là phần tử $tach_hoten[$n-1]; Mã cụ thể:

$str = "nguyễn đức anh";
$tach_hoten = preg_split('/\s+/', $str);;

$t = count($tach_hoten) - 1;

echo $tach_hoten[$t];

4. Thống kê đệm

Đệm là thành phần không bắt buộc phải có trong họ tên, nhưng nó rất thường xuyên được sử dụng, đặc biệt là nữ.

Một họ tên có đệm thì nó cần có số từ ít nhất là 3. Các từ nằm giữa họ và tên được gọi là đệm.

Đoạn mã lấy đệm như sau:

$str = "nguyễn ngọc bảo châu";
$tach_hoten = preg_split('/\s+/', $str);;

$n = count($tach_hoten);

$dem='';

if ($n==3) {$dem = $tach_hoten[1];}

if ($n>3) {
    $d = $n-1;
    for($i=1;$i<$d;$i++) {
        $dem=$dem.$tach_hoten[$i]." ";
    }
}

echo $dem;

Đoạn mã trên có nghĩa là:

  • Nếu tên có 3 từ, thì đệm là phần tử thứ 2, nghĩa là $tach_hoten[1] (lưu ý, mảng được đánh thứ tự từ 0);
  • Nếu tên có trên 3 từ, thì đệm được tạo bằng cách nối chuỗi từ phần tử thứ hai $tach_hoten[1] đến phần tử ngay trước tên $tach_hoten[$n-2];
  • Nếu tên có 2 từ, $dem trả về giá trị rỗng ”;

5. Thống kê số từ trong tên

Cái này nên thực hiện phân theo giới tính và chung cho cả hai. Phân loại theo giới sẽ cho kết quả thú vị, vì tên nữ có khuynh hướng dài hơn tên nam đáng kể.

Hàm để xác định số từ chính là count($tach_hoten). Chúng ta tạo cột sotu để ghi lại thông tin này. Sau đó cộng vào và chia trung bình (mẫu số là số lượng tên).

6. Số ký tự trong tên

Cũng nên phân theo giới tính và thống kê chung. Số lượng ký tự sẽ tính cả khoảng trắng, cho nên cần đảm bảo loại trừ khoảng trắng dư ở 2 bên cũng như trong họ tên, cái này nếu chúng ta dùng hàm chuan_hoa_hoten là xử lý được rồi.

Câu lệnh chúng ta dùng để đếm là iconv_strlen($str, 'UTF-8'), nó sẽ đếm ký tự dựa trên bảng mã UTF-8 là bảng mã tiếng Việt mà chúng ta dùng.

Lưu ý ở phần này là kết quả sẽ sai lệch nếu chúng ta sử dụng họ tên được mã hóa theo kiểu ít dùng. Ví dụ ễ theo kiểu ít dùng được tính là 2 ký tự vì là kết hợp của ê và dấu ngã. Kiểu thường dùng ễ sẽ cho kết quả 1 ký tự, và cái này mới giúp kết quả chính xác.

Để khắc phục vấn đề mã hóa chúng ta dùng hàm chuyen_ma_hoa;

Ví dụ về kết quả thống kê số lượng ký tự của 2 dạng mã hóa:

$str1 = "nguyễn ngọc bảo châu"; // mã hóa theo kiểu ít phổ biến 
$str2 = "nguyễn ngọc bảo châu"; // mã hóa theo kiểu phổ biến

echo iconv_strlen($str1, 'UTF-8')."</br>"; // kết quả sai khi nó tính thêm 3 ký tụ ngã, nặng, hỏi
echo iconv_strlen($str2, 'UTF-8'); // kết quả chính xác khi ê, ọ và ả được tính là 3 ký tự chứ không phải 6 như $str1

Lưu ý là kể cả bạn dùng bảng mã utf8mb4_general_ci thì khi dùng lệnh PHP nó vẫn cho kết quả khác biệt. Do vậy điều quan trọng là phải chuẩn hóa nó về dạng mã hóa phổ biến.

Bạn có thể kiểm tra bằng cách thử câu lệnh sau:

    session_start();
    ob_start();
    require 'database.php'; // tai database
   
    $query3="SELECT * FROM khacmahoa";
    $result3=$db->query($query3); 
    $str = array(); $i=0;
    foreach ($result3 as $value3) {
          $str[$i] = $value3['hoten'];
          $i++;
    }
echo iconv_strlen($str[0], 'UTF-8')."</br>"; // kết quả sai khi nó tính thêm 3 ký tụ ngã, nặng, hỏi
echo iconv_strlen($str[1], 'UTF-8'); // kết quả chính xác khi ê, ọ và ả được tính là 3 ký tự chứ không phải 6 như $str1

Trong đó bảng khacmahoa chỉ cần chứa 2 tên có kiểu hình giống nhau nhưng được mã hóa khác nhau trong cột hoten.

Ngoài việc tính số lượng ký tự trung bình. Chúng ta có thể tính thêm trung vị, vì số lượng ký tự trong tên biến thiên khá nhiều, có thể chủ từ 8 ký tự cho đến hơn 20 ký tự.

7. Về đệm Văn và Thị

Đây là 2 đệm phổ biến trong giới nam và nữ, nhưng có khuynh hướng giảm hoặc cần kết hợp thêm từ như trong nữ để tên hay hơn.

Để tìm xem một chuỗi cụ thể có trong chuỗi nào đó hay không, chúng ra dùng hàm mb_strpos. Nếu có nó sẽ trả về vị trí của chuỗi tính theo số ký tự từ trái qua phải.

$str1 = "nguyễn thị kim dung"; 
$str2 = "lê văn nam";
$str3 = "nguyễn đức anh";
$str4 = "ngô thị minh tâm";

echo mb_strpos($str1,"thị"); // cho kết quả 7
echo "</br>";
echo mb_strpos($str2,"văn"); //cho kết quả 3
echo "</br>";
echo mb_strpos($str3,"văn"); // kết quả rỗng vì không có
echo "</br>";
echo mb_strpos($str1,"thị"); // vẫn cho ra kết quả 7 dù $str4 có từ thị được mã hóa không phổ thông

Một số lưu ý:

  • Hàm mb_strpos có phân biệt chữ hoa, chữ thường, do vậy cần lưu ý thống nhất định dạng họ tên về chữ thường để tiện kiểm tra;
  • Một hàm tương tự mb_strposstrpos, nếu bạn dùng strpos vẫn cho kết quả, nhưng giá trị sẽ lớn hơn, chứ không chính xác vị trí;
  • Hàm stripos tương tự hàm strpos, nhưng không phân biệt chữ hoa chữ thường, tuy nhiên chỉ đúng với ký tự Latinh, các ký tự tiếng Việt có dấu sẽ trả về kết quả sai;
  • Kết luận: nên dùng mb_strpos để cho kết quả chính xác nhất.
Back to Top