[PHP] Note viết hàm chuyển mã (Encoding) tiếng Việt từ TCVN3 sang Unicode

Table of Contents

[PHP] Note viết hàm chuyển mã (Encoding) tiếng Việt từ TCVN3 sang Unicode

Hôm nay lại bàn về vấn để chuyển mã từ font Tiêu chuẩn Việt Nam 3 (TCVN3) sáng bảng mã quốc tế Unicode. Lý do là vì hôm trước tìm được thư viện UConvert tưởng tìm được chân kinh, nhưng không ngờ áp dụng vô thực tế cái đang làm không được

https://dothanhlong.org/unicode-va-ma-hoa-ky-tu-cu-cua-viet-nam/

Mặc dù đã khai báo, nhưng cứ hễ gọi cái class UConvert từ trong một hàm nào đó là nó báo lỗi không tìm thấy @@!

image

Lỗi class UConvert

Vậy là đành phải tự viết một cái function chuyển đổi bảng mã thôi :'), cậy người không bằng cậy mình :v Nói vậy chứ mình cũng dạo thêm một vòng Google xem có ai làm chưa, thì thấy có một người có làm, nhưng làm chưa đến nơi.

Hàm chuyển mã Unicode sang VNI

Hàm chuyển mã tiếng Việt Unicode sang VNI, dùng thủ thuật tìm và thay thế từng âm tiết

function UNI_2_VNI ( $text2 )
{
 $text = utf8_encode($text2);
 $UNI = array ("À","à ","Ã�","á","Â","â","Ã","ã","È","è","É","é","Ê","ê","ÃŒ","ì","Ã�","í","Ã’","ò","Ó","ó","Ô","ô","Õ","õ","Ù","ù","Ú","ú","Ã�","ý","Ä‚","ă","Ä�","Ä‘","Ĩ","Ä©","Ũ","Å©","Æ ","Æ¡","Ư","Æ°","Ạ","ạ","Ả","ả","Ấ","ấ","Ầ","ầ","Ẩ","ẩ","Ẫ","ẫ","Ậ","ậ","Ắ","ắ","Ằ","ằ","Ẳ","ẳ","Ẵ","ẵ","Ặ","ặ","Ẹ","ẹ","Ẻ","ẻ","Ẽ","ẽ","Ế","ế","Ề","á»�","Ể","ể","Ễ","á»…","Ệ","ệ","Ỉ","ỉ","Ị","ị","Ọ","á»�","Ỏ","á»�","á»�","ố","á»’","ồ","á»”","ổ","á»–","á»—","Ộ","á»™","Ớ","á»›","Ờ","á»�","Ở","ở","á» ","ỡ","Ợ","ợ","Ụ","ụ","Ủ","ủ","Ứ","ứ","Ừ","ừ","Ử","á»­","á»®","ữ","á»°","á»±","Ỳ","ỳ","á»´","ỵ","Ỷ","á»·","Ỹ","ỹ");
 $VNI = array ("","","","","","","","","","","","","","","Ì","ì","Í","í","","","","","","","","","","","","","","","","","Ñ","ñ","Ó","ó","","","Ô","ô","Ö","ö","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Æ","æ","Ò","ò","","","","","","","","","","","","","","","ÔÙ","ôù","ÔØ","ôø","ÔÛ","ôû","ÔÕ","ôõ","ÔÏ","ôï","","","","","ÖÙ","öù","ÖØ","öø","ÖÛ","öû","ÖÕ","öõ","ÖÏ","öï","","","Î","î","","","","");
 for ($i = 0; $i < count($UNI); $i++)
 {
  $text = str_replace($UNI[$i], $VNI[$i], $text);
 }
 return $text;
}

Cách dùng

echo UNI_2_VNI("Xin chào các bạn, đây là chuỗi tiếng Việt Unicode đã được chuyển sang VNI");

Mở rộng

Bạn cũng có thể thay thế đoạn code này

$text = str_replace($UNI[$i], $VNI[$i], $text);

Thành thế này

$text = str_replace($VNI[$i], $UNI[$i], $text);

Để thực hiện việc chuyển từ mã VNI sang Unicode.Ngoài ra, bạn cũng có thể dùng Unikey, chuyển nội dung mảng $VNI thành những bảng mã khác.Ví dụ: Hàm chuyển từ bảng mã Unicode sang TCVN3

function UNI_2_TCVN3 ( $text )
{
 $UNI = array ( "à", "á", "", "ã", "", "ă", "", "", "", "", "", "â", "", "", "", "", "", "đ", "è", "é", "", "", "", "ê", "", "ế", "", "", "", "ì", "í", "", "ĩ", "", "ò", "ó", "", "õ", "", "ô", "", "", "", "", "", "ơ", "", "", "", "", "", "ù", "ú", "", "ũ", "", "ư", "", "", "", "", "", "", "ý", "", "", "", "Ă", "Â", "Đ", "Ê", "Ô", "Ơ", "Ư");
 $TCVN3 = array ( "µ", "¸", "", "·", "¹","¨", "»", "¾", "¼", "½", "Æ","©", "Ç", "Ê", "È", "É", "Ë","®", "Ì", "Ð", "Î", "Ï", "Ñ","ª", "Ò", "Õ", "Ó", "Ô", "Ö","×","Ý", "Ø", "Ü", "Þ","ß", "ã", "á", "â", "ä","«", "å", "è", "æ", "ç", "é","¬", "ê", "í", "ë", "ì", "î", "ï", "ó", "ñ", "ò", "ô", "­", "õ", "ø", "ö", "÷", "ù","ú", "ý", "û", "ü", "þ", "¡", "¢", "§", "£", "¤", "¥", "¦");
 for ($i = 0; $i < count($UNI); $i++)
 {
  $text = str_replace($UNI[$i], $TCVN3[$i], $text);
 }
 return $text;
}

https://kingno1.wordpress.com/2010/10/04/ham-chuy%E1%BB%83n-ma-unicode-sang-vni/

Tại sao mình nói là chưa đến nơi.

  • Thứ nhất vì bảng mã của Unicode và TCVN3 bạn này dùng mình thấy chưa chuẩn, mình dùng lại thì convert từ Unikey sang khác với của bạn này.
  • Thứ hai là thuật toán chưa hợp lý. Bạn này chỉ dùng hàm str_replace để thay thế ký tự đơn thuần từ TCVN3 sang UNICODE, tuy nhiên khi chạy vòng lặp lại là lặp hết mảng UNICODE hoặc TCVN3, đều này dẫn đến là nếu một chuỗi có một ký tự chuyển từ TCVN3 sang UNICODE ra 1 ký tự, ký tự này lại nằm trong mảng TCVN3 nữa thì nó sẽ lại bị thay thế một lần nữa.

Ví dụ trường hợp mình bị là đối với chuỗi

ch©u ®èc

Chuỗi này chuyển sang UNICODE đúng là châu đốc

châu đốc

Tuy nhiên khi dùng cách chuyển như bạn thì từ © trong từ ch©u sẽ bị chuyển thành â, từ â lại bị chuyển thành

Kết quả mình có:

image

Lỗi font

Để khắc phục mình đưa ra ý tưởng là thay vì lập hết mảng TCVN3 hay Unicode thì mình duyệt qua từ ký tự của chuỗi. Sau đó xác định vị trí của ký tự trong mảng TCVN3, thay thế nó bằng ký tự ở mảng Unicode ở vị trí tương ứng. Như vậy mỗi ký tự trong chuỗi chỉ được duyệt qua và thay thế 1 lần thôi. Tránh tình trạng bị thay thế 2 lần như cách của bạn ở trên.

Cuối cùng ráp lại ta có chuỗi mới.

Thực hiện cải tiến Hàm chuyển mã Unicode sang VNI

Đầu tiên tạo một mảng chứa các ký tự Unicode

$UNI = array("À","Á","Â","Ã","È","É","Ê","Ì","Í","Ò","Ó","Ô","Õ","Ù","Ú","Ý","à","á","â","ã","è","é","ê","ì","í","ò","ó","ô","õ","ù","ú","ý","Ă","ă","Đ","đ","Ĩ","ĩ","Ũ","ũ","Ơ","ơ","Ư","ư","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","ế","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
);

Sau đó mình dùng Unikey convert cái này sang TCVN3 để có mảng các ký tự theo TCVN3

image

Unikey convert sang TCVN3

$TCVN3 = array("µ","¸","¢","·","Ì","Ð","£","×","Ý","ß","ã","¤","â","ï","ó","ý","µ","¸","©","·","Ì","Ð","ª","×","Ý","ß","ã","«","â","ï","ó","ý","¡","¨","§","®","Ü","Ü","ò","ò","¥","¬","¦","­","¹","¹","","","Ê","Ê","Ç","Ç","È","È","É","É","Ë","Ë","¾","¾","»","»","¼","¼","½","½","Æ","Æ","Ñ","Ñ","Î","Î","Ï","Ï","Õ","Õ","Ò","Ò","Ó","Ó","Ô","Ô","Ö","Ö","Ø","Ø","Þ","Þ","ä","ä","á","á","è","è","å","å","æ","æ","ç","ç","é","é","í","í","ê","ê","ë","ë","ì","ì","î","î","ô","ô","ñ","ñ","ø","ø","õ","õ","ö","ö","÷","÷","ù","ù","ú","ú","þ","þ","û","û","ü","ü"
);

Bây giờ đến giai đoạn tách chuỗi, ban đầu mình dùng hàm str_split, nhưng hàm này tách riêng từng byte (từng char, ngay cả dấu sắc, dấu hỏi,..) Do mình dùng tiếng Việt là mã Multi byte, do vậy mình đã sửa chuyển sang dùng hàm mb_split

$arr1=mb_split($text,'UTF-8');

Và để đếm ký tự multi byte thì cũng có hàm riêng cho nó

$len = mb_strlen($text, 'UTF-8');

Cái vòng lập duyệt qua từng char

for($i=0;$i<$len; $i++){
        $char=mb_substr($text, $i, 1, 'UTF-8');
        $result[] = $char;
        //echo mb_substr($text, $i, 1, 'UTF-8');
        //echo '<br>';
        $key=array_search($char,$TCVN3);
        echo $char.' co ma: '.$key;
        echo '<br>';
        if($key!=''){
            $arr2[$i]=$UNI[$key];
        }else{
            $arr2[$i]=$char;
        }
    }

Cuối cùng, ráp mảng kết quả lại bằng hàm implode

$text=implode("",$arr2);

Code full hàm chuyển đổi bảng mã tiếng Việt TCVN3 sang Unicode của mình

function TCVN3_2_UNI($text){
    $UNI = array("À","Á","Â","Ã","È","É","Ê","Ì","Í","Ò","Ó","Ô","Õ","Ù","Ú","Ý","à","á","â","ã","è","é","ê","ì","í","ò","ó","ô","õ","ù","ú","ý","Ă","ă","Đ","đ","Ĩ","ĩ","Ũ","ũ","Ơ","ơ","Ư","ư","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","ế","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
);
    $TCVN3 = array("µ","¸","¢","·","Ì","Ð","£","×","Ý","ß","ã","¤","â","ï","ó","ý","µ","¸","©","·","Ì","Ð","ª","×","Ý","ß","ã","«","â","ï","ó","ý","¡","¨","§","®","Ü","Ü","ò","ò","¥","¬","¦","­","¹","¹","","","Ê","Ê","Ç","Ç","È","È","É","É","Ë","Ë","¾","¾","»","»","¼","¼","½","½","Æ","Æ","Ñ","Ñ","Î","Î","Ï","Ï","Õ","Õ","Ò","Ò","Ó","Ó","Ô","Ô","Ö","Ö","Ø","Ø","Þ","Þ","ä","ä","á","á","è","è","å","å","æ","æ","ç","ç","é","é","í","í","ê","ê","ë","ë","ì","ì","î","î","ô","ô","ñ","ñ","ø","ø","õ","õ","ö","ö","÷","÷","ù","ù","ú","ú","þ","þ","û","û","ü","ü"
);
    $arr1=mb_split($text,'UTF-8');
    $arr2=array();
    $len = mb_strlen($text, 'UTF-8');
    for($i=0;$i<$len; $i++){
        $char=mb_substr($text, $i, 1, 'UTF-8');
        $result[] = $char;
        //echo mb_substr($text, $i, 1, 'UTF-8');
        //echo '<br>';
        $key=array_search($char,$TCVN3);
        echo $char.' co ma: '.$key;
        echo '<br>';
        if($key!=''){
            $arr2[$i]=$UNI[$key];
        }else{
            $arr2[$i]=$char;
        }
    }
    $text=implode("",$arr2);
    //echo $text;
    //echo $result[1];
    /* for($i=0;$i<count($arr1);$i++){
        $key=array_search($arr1[$i],$TCVN3);
        echo $arr1[$i].' co ma: '.$key;
        echo '<br>';
        $arr2[$i]=$UNI[$key];
    } */
    //$text=implode("",$arr2);
    /* for ($i=0;$i<count($UNI);$i++){
        $text = str_replace($TCVN3[$i], $UNI[$i], $text);
    } */
    return $text;
}

Kết quả

image

Hàm php chuyển mã tiếng Việt

Hi vọng giúp được mọi người, đối với các bảng mã khác cũng tương tụ vậy nhé -soiqualang_chentreu-

Tham khảo

  1. https://stackoverflow.com/questions/38126940/php-str-split-and-utf8-polish-characters
  2. https://stackoverflow.com/questions/29710635/fatal-error-call-to-undefined-function-mb-split
  3. http://php.net/manual/en/function.mb-split.php
  4. https://www.w3schools.com/php/func_string_implode.asp
  5. http://php.net/manual/en/function.str-split.php
  6. https://stackoverflow.com/questions/2959222/get-the-index-value-of-an-array-in-php

Leave a Reply

Your email address will not be published. Required fields are marked *