[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 @@!
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 ("AØ","aø","AÙ","aù","AÂ","aâ","AÕ","aõ","EØ","eø","EÙ","eù","EÂ","eâ","Ì","ì","Í","í","OØ","oø","OÙ","où","OÂ","oâ","OÕ","oõ","UØ","uø","UÙ","uù","YÙ","yù","AÊ","aê","Ñ","ñ","Ó","ó","UÕ","uõ","Ô","ô","Ö","ö","AÏ","aï","AÛ","aû","AÁ","aá","AÀ","aà","AÅ","aå","AÃ","aã","AÄ","aä","AÉ","aé","AÈ","aè","AÚ","aú","AÜ","aü","AË","aë","EÏ","eï","EÛ","eû","EÕ","eõ","EÁ","eá","EÀ","eà","EÅ","eå","EÃ","eã","EÄ","eä","Æ","æ","Ò","ò","OÏ","oï","OÛ","oû","OÁ","oá","OÀ","oà","OÅ","oå","OÃ","oã","OÄ","oä","ÔÙ","ôù","ÔØ","ôø","ÔÛ","ôû","ÔÕ","ôõ","ÔÏ","ôï","UÏ","uï","UÛ","uû","ÖÙ","öù","ÖØ","öø","ÖÛ","öû","ÖÕ","öõ","ÖÏ","öï","YØ","yø","Î","î","YÛ","yû","YÕ","yõ");
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ó:
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("À","Á","Â","Ã","È","É","Ê","Ì","Í","Ò","Ó","Ô","Õ","Ù","Ú","Ý","à","á","â","ã","è","é","ê","ì","í","ò","ó","ô","õ","ù","ú","ý","Ă","ă","Đ","đ","Ĩ","ĩ","Ũ","ũ","Ơ","ơ","Ư","ư","Ạ","ạ","Ả","ả","Ấ","ấ","Ầ","ầ","Ẩ","ẩ","Ẫ","ẫ","Ậ","ậ","Ắ","ắ","Ằ","ằ","Ẳ","ẳ","Ẵ","ẵ","Ặ","ặ","Ẹ","ẹ","Ẻ","ẻ","Ẽ","ẽ","Ế","ế","Ề","ề","Ể","ể","Ễ","ễ","Ệ","ệ","Ỉ","ỉ","Ị","ị","Ọ","ọ","Ỏ","ỏ","Ố","ố","Ồ","ồ","Ổ","ổ","Ỗ","ỗ","Ộ","ộ","Ớ","ớ","Ờ","ờ","Ở","ở","Ỡ","ỡ","Ợ","ợ","Ụ","ụ","Ủ","ủ","Ứ","ứ","Ừ","ừ","Ử","ử","Ữ","ữ","Ự","ự","Ỳ","ỳ","Ỵ","ỵ","Ỷ","ỷ","Ỹ","ỹ"
);
Unikey convert cái này sang TCVN3 để có mảng các ký tự theo TCVN3
Sau đó mình dùng
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;
}
}
implode
Cuối cùng, ráp mảng kết quả lại bằng hàm
$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ả
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
- https://stackoverflow.com/questions/38126940/php-str-split-and-utf8-polish-characters
- https://stackoverflow.com/questions/29710635/fatal-error-call-to-undefined-function-mb-split
- http://php.net/manual/en/function.mb-split.php
- https://www.w3schools.com/php/func_string_implode.asp
- http://php.net/manual/en/function.str-split.php
- https://stackoverflow.com/questions/2959222/get-the-index-value-of-an-array-in-php