Xây dựng các hàm căn bản để xử lý chuỗi họ tên người nói riêng và tiếng Việt nói chung

PHP có nhiều hàm hay để xử lý chuỗi, tuy nhiên nó vẫn mạnh và có các hàm phổ biến xử lý cho tiếng Tây tốt hơn là tiếng Việt. Trong ngày hôm nay tôi sẽ thử viết một số hàm xử lý cơ bản hoặc thực hiện một nhiệm vụ đặc thù để quá trình viết mã được nhanh hơn và hạn chế lỗi do dùng nhầm hàm không xử lý tốt tiếng Việt.

Biến đầu vào tên $str đại diện cho chuỗi.

Quy định về viết tên hàm (đây là rule riêng của tôi thôi, các bạn không cần quan tâm phần này, vì mỗi người có thể có kiểu phù hợp riêng):

  • Tiếng Việt không dấu, mỗi từ là một dấu gạch dưới, tối đa 2 dấu gạch dưới;
  • Viết tắt các từ trên 4 ký tự. Ví dụ thay vì bo_khoang_trang, đổi thành bkt;
  • kt trong tên hàm mà đứng trước hoặc sau là dấu gạch dưới _ thì nó là từ viết tắt dành riêng cho ký tự, các từ khác nếu trùng thì phải viết liền với ký tự khác (như bkt) ở trên hoặc phải viết ở dạng đầy đủ;

Quy định về viết mã:

  • Các hàm đã viết mã trước đó mà hàm sau dùng lại tác vụ đó thì nên lồng hàm để tối thiểu dòng mà và tránh sai sót;
  • Các biến trong hàm cần rõ ràng, tránh ghi đè không chủ động;
  • Có chú thích đầy đủ để dễ hiểu, và tiện sửa chữa;
  • Không viết hàm mà PHP đã có hàm tương đương để xử lý (anh chị em nào đọc thấy có hàm thì bình luận để tôi biết nhé);
  • Có khoảng trắng đằng sau dấu ,
  • Biến kết quả ký hiệu là $kq, và return về đây cho thống nhất;
  • Có dòng trắng ngay trước return;
  • Biến số trong hàm nên để là $n;
  • Biến chạy vòng lặp nên để là $i, $j, $k;
  • Ngoại trừ biến vòng lặp, các biến khác dấu = nên có khoảng trắng ở trước và sau;

Loại bỏ khoảng trắng dư thừa trong chuỗi:

function bkt($str) { // bỏ khoảng trắng
    $str2 = trim($str, ' '); // bỏ khoảng trắng trước và sau chuỗi
    $kq = preg_replace('/\s+/', ' ', $str2); // loại bỏ khoảng trắng thừa trong chuỗi

return $kq;
}

Đếm số ký tự trong chuỗi, bao gồm cả khoảng trắng, dùng trong trường hợp không chắc chắn giữa các từ có bị dư khoảng trắng hay là không:

function so_kt($str) { // số ký tự chuỗi
    $str2 = bkt($str);
    $kq = iconv_strlen($str2, 'UTF-8');

return $kq;
} 

Đếm số từ trong chuỗi, hàm str_word_count của PHP cho kết quả không chính xác với TV, hàm thay thế sẽ như thế này:

function so_tu($str) { // số lượng từ
    $str2 = bkt($str); 
    $word = explode(' ', $str2);
    $kq = count($word); // so tu

return $kq;
}

Lấy từ đầu tiên trong chuỗi:

function tu_01($str) { // trong họ tên nó sẽ là họ
    $str2 = bkt($str); // có thể không cần dùng lbk_trang
    $word = explode(' ', $str2);
    $kq = $word[0]; // từ đầu tiên

return $kq;
}

Lấy từ cuối cùng trong chuỗi:

function tu_99($str) { // trong họ tên nó sẽ là tên
    $str2 = bkt($str); // có thể không cần dùng lbk_trang
    $word = explode(' ', $str2);
    $n = count($word)-1;
    $kq = $word[$n]; // từ đầu tiên

return $kq;
}

Từ thứ 2 trong chuỗi, nếu chuỗi là họ tên thì đây sẽ là đệm:

function tu_02($str) { // đệm đầu tiên
    $kq = NULL;
    $str2 = bkt($str); // có thể không cần dùng lbk_trang
    $word = explode(' ', $str2);
    $n = count($word);
    if ($n > 2) {$kq = $word[1];}

return $kq;
}

Có các ký tự f, j, w, z trong chuỗi hay không?

function kt_nng($str) { // trả về 1 nếu có, trả về 0 nếu không có
    $m = array("f","j","w","z");
    foreach ($m as $m2) {
        $pt = '/'.$m2.'/';
        $kk = preg_match($pt, $str);
        if ($kk > 0) {$kq=1;break;} 
        else {$kq=0;}    
    }
    
return $kq;    
}

Kiểm tra xem có số trong chuỗi hay không:

function tim_so($str) {
    $kq=0;
    $m = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); 

    foreach ($m as $m2) {
        $pt='/'.$m2.'/';
        $kk = preg_match($pt, $str);
        if ($kk > 0) {$kq=1;break;}    
    }
    
return $kq;
}

Kiểm tra xem có ký tự lạ trong chuỗi hay không (ví dụ !, @, #, ..):

function kt_la($str) {
    $kq = 0;
    $m = array('\!', '\~', '\/', '\@', '\#','\$', '\%', '\'', '\^', '\&', '\*', '\(', '\)', '\-', '\_', '\=', '\+', '\[', '\{', '\]', '\}', '\|', '\:', '\;', '\"', '\,', '\<', '\.', '\>', '\?', '\+'); // ký tự dư

foreach ($m as $m2) {
        $pt ='/'.$m2.'/';
        $kk = preg_match($pt, $str);
        if ($kk > 0) {$kq=1;break;}   
    }
    
return $kq;
}

Tìm dấu của một từ hoặc một ký tự là sắc (1), huyền (2), hỏi (3), ngã (4), nặng (5) hay không dấu (0).

function tim_dau($str) { 
$kq=0;
        $sac = array("á","ắ","ấ","é","ế","ó","ố","ớ","ú","ứ","ý","í"); // kq 1

        $huyen = array("à","ằ","ấ","è","ề","ò","ồ","ờ","ù","ừ","ỳ","ì"); // kq 2

        $hoi = array("ả","ẳ","ẩ","ể","ẻ","ỏ","ổ","ở","ủ","ử","ỷ","ỉ"); // kq 4

        $nga = array("ã","ẵ","ẫ","ẽ","ễ","õ","ỗ","ỡ","ũ","ữ","ỹ","ĩ"); // kq 4

        $nang = array("ạ","ặ","ậ","ẹ",'ệ',"ọ","ộ","ợ","ụ","ự","ỵ","ị"); // kq 4
        
foreach ($sac as $s2) {
        $pt2 ='/'.$s2.'/';
        $kk2 = preg_match($pt2, $str);
        if ($kk2 > 0) {$kq="1";break;}   
    }
    
foreach ($huyen as $s3) {
        $pt3 ='/'.$s3.'/';
        $kk3 = preg_match($pt3, $str);
        if ($kk3 > 0) {$kq="2";break;}   
    }

foreach ($hoi as $s4) {
        $pt4 ='/'.$s4.'/';
        $kk4 = preg_match($pt4, $str);
        if ($kk4 > 0) {$kq="3";break;}  
    } 

foreach ($nga as $s5) {
        $pt5 ='/'.$s5.'/';
        $kk5 = preg_match($pt5, $str);
        if ($kk5 > 0) {$kq="4";break;}   
    } 

foreach ($nang as $s6) {
        $pt6 ='/'.$s6.'/';
        $kk6 = preg_match($pt6, $str);
        if ($kk6 > 0) {$kq="5";break;} 
    }     
    
return $kq;
}

So sánh mức độ tương tự giữa 2 chuỗi. Với 4 biến đầu vào. $v chỉ giá trị levenshtein bạn mong muốn tối thiểu phải đạt được, còn $p là giá trị có được từ hàm similar_text của PHP. Đây là hai hàm tốt dùng để so sánh chuỗi.

function tt_85($str2, $str3, $v, $p){
    $kq = 0;
    $ven = levenshtein($str2,$str3,1,1,1);
    similar_text($str2, $str3, $per);
    if ($v >= $ven && $per > $p) {$kq=1;}

return $kq;
}

Tìm số lượng của một ký tự nào đó trong chuỗi

function kt_bbb($str, $t) {
        $kq=0;
        $str2 = preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);
        foreach ($str2 as $mt2) {
                        if($mt2==$t) {$kq++;}
        }
 
return $kq;    
}

Xóa dấu của một từ, hoặc một ký tự (nếu từ đó có nhiều dấu, nó cũng xóa hết):

function xoa_dau($str){ 
    $dx = array("cc80","cc81","cc83","cc89","cca3"); // mã hóa dấu tiếng Việt
    $hz = bin2hex(mahoa_itdung($str)); // chuyển sang mã hex để tìm dấu
    
    $i=0;

foreach ($dx as $dy) { 
             $dz ='/'.$dy.'/';
                  if (preg_match($dz, $hz)) {
                      $hz = preg_replace($dz,'',$hz); // khử dấu của $hz; nó vẫn đang ở dạng hex
                      $i++;
                  } 
    }

    $kq = chuyen_ma_hoa(hex2bin($hz)); 

return $kq;
}

Thêm dấu cho một ký tự (cái này chỉ dùng để thêm dấu cho một ký tự, không thêm dấu cho một từ được, vì sẽ không chính xác).

function them_dau($str, $d){
$str2=xoa_dau($str);
$dau="";
            if ($d==1) {$dau="cc81";} // sắc

            if ($d==2) {$dau="cc80";} // huyền

            if ($d==3) {$dau="cc89";} // hỏi

            if ($d==4) {$dau="cc83";} // ngã

            if ($d==5) {$dau="cca3";} // nặng

            $hx = bin2hex(mahoa_itdung($str2)); 
            $hx.=$dau; 

$kq = chuyen_ma_hoa(hex2bin($hx));

return $kq; 
}

Lấy n ký tự đầu của một chuỗi:

function catn_kt($str, $n) {
        $i = 0; $kq = "";
        $str2 = preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);
        foreach ($str2 as $mt2) {
                        if($i<$n) {$kq.=$mt2;}
                        $i++;
        }
 
return $kq;    
}

Tìm các vị trí của một ký tự trong chuỗi:

function vi_tri($str, $kt) { // vị trí ký tự theo kiểu con người
        $kq = array(); $i=1; $j=0;
        $str2 = preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);
        foreach ($str2 as $mt2) {
                        if($mt2==$kt) {$kq[$j]=$i;$j++;}
                        $i++;
        }
 
return $kq; // kết quả đưa vào mảng    
}

Thay thế một ký tự trong chuỗi ở một vị trí ($vt) nhất định bằng ký tự khác ($kt):

function thay_the($str,$kt,$vt) {
        $i=1; $kq="";$mt3=array();
        $str2 = preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);

        foreach ($str2 as $mt2) {
                        if($vt == $i) {$mt2=$kt;}
                        $mt3[$i]=$mt2;
                        $i++;
        }
        
        foreach ($mt3 as $mt4) {
            $kq.=$mt4;
        }
return $kq;    
}

Leave a Comment