แปลง UTF-8 เป็น TIS-620 ไป ๆ กลับ ๆ ใน .NET Core
ได้ไปทำงานกับลูกค้าที่มี project เก่า ๆ บางตัวที่ยังใช้ข้อมูลในฐานข้อมูลที่มี character set เป็น tis-620 อยู่ และไม่สามารถแปลงเป็น utf-8 ได้ด้วยสาเหตุอะไรบางอย่าง (น่าจะเป็นงานที่จะงอกขึ้นมากับทุก ๆ ระบบที่เค้า live อยู่) รู้แค่ว่า project ใหม่ ๆ ยังต้องไปดึงข้อมูลจากฐานข้อมูลนี้ แถมอีก project ต้องส่งข้อมูลที่เป็น utf-8 ไปหาระบบที่รองรับแต่ tis-620 อีก นั่นคือ ต้องมีวิธีแปลงข้อมูลจาก tis-620 ไปเป็น utf-8 และแปลงจาก utf-8 กลับไปเป็น tis-620
ข่าวร้ายคือ ใน .NET Core Framework ยกเลิกการ support legacy character set บางภาษาไปแล้ว รวมถึงภาษาไทยด้วย นั่นคือ วิธีการ convert encoding ที่ควรจะทำได้ง่าย ๆ มันไม่ง่ายอีกต่อไป
วิธีการตรงไปตรงมาคือ google หาวิธีแปลงจากในเว็บนี่แหละ ก็ไปเจอวิธีแปลงที่มีคนเขียนไว้ของ php (แบบไม่ได้ใช้ iconv) เป็นวิธีแปลงทีละตัวอักษร และเอาผลลัพธ์ที่ได้ไปต่อกันเป็น output ก็เลยลอง port มาเป็น .NET Core ดู ได้ประมาณนี้
using System;
using System.Collections.Generic;
using System.Text;public static class ThaiEncodingService {
public static byte[] ToTIS620(string utf8String) {
List<byte> buffer = new List<byte>();
byte utf8Identifier = 224;
for (var i = 0; i < utf8String.Length; i++) {
string utf8Char = utf8String.Substring(i, 1);
byte[] utf8CharBytes = Encoding.UTF8.GetBytes(utf8Char);
if (utf8CharBytes.Length > 1 && utf8CharBytes[0] == utf8Identifier) {
var tis620Char = (utf8CharBytes[2] & 0x3F);
tis620Char |= ((utf8CharBytes[1] & 0x3F) << 6);
tis620Char |= ((utf8CharBytes[0] & 0x0F) << 12);
tis620Char -= (0x0E00 + 0xA0);
byte tis620Byte = (byte)tis620Char;
tis620Byte += 0xA0;
tis620Byte += 0xA0;buffer.Add(tis620Byte);
} else {
buffer.Add(utf8CharBytes[0]);
}
}
return buffer.ToArray();
}public static byte[] ToUTF8(byte[] tis620Bytes) {
List<byte> buffer = new List<byte>();
byte safeAscii = 126;
for (var i = 0; i < tis620Bytes.Length; i++) {
if (tis620Bytes[i] > safeAscii) {
if (((0xa1 <= tis620Bytes[i]) && (tis620Bytes[i] <= 0xda))
|| ((0xdf <= tis620Bytes[i]) && (tis620Bytes[i] <= 0xfb))) {
var utf8Char = 0x0e00 + tis620Bytes[i] - 0xa0;byte utf8Byte1 = (byte)(0xe0 | (utf8Char >> 12));
buffer.Add(utf8Byte1);
byte utf8Byte2 = (byte)(0x80 | ((utf8Char >> 6) & 0x3f));
buffer.Add(utf8Byte2);
byte utf8Byte3 = (byte)(0x80 | (utf8Char & 0x3f));
buffer.Add(utf8Byte3);
}
} else {
buffer.Add(tis620Bytes[i]);
}
}
return buffer.ToArray();
}
}
จากโค้ดด้านบน ตอนแปลง จาก utf-8 เป็น tis-620 ก็ตรงไปตรงมา โยน utf-8 เข้ามา รับเป็น tis-620 กลับไป สังเกตว่าตอนรับกลับไปรับไปเป็น byte[] เพราะว่าใน dotnet core มันไม่ support string ที่เป็น tis-620 แล้ว
ส่วนตอนแปลงจาก tis-620 ไปเป็น utf-8 ก็เหมือนกัน ต้องรับมาเป็น byte[] ด้วยเหตุผลเดียวกัน ตอนรับกลับไปก็เป็น byte[] ถ้าอยากได้เป็น string ก็ค่อยไปแปลงเอง ด้วย Encoding.UTF8.GetString() ไม่ได้ยากอะไร
ตัวอย่างอยู่ที่ https://github.com/chonla/dotnet-thai-charset-conversion
ป.ล.
- ทำเป็น Nuget package แล้ว เผื่อใครจะเอาไปใช้กัน https://www.nuget.org/packages/Chonla.ThaiEncoding/
- ตัวอย่างใน github มีการเอา Linq มาใช้ ทำให้อ่านง่ายขึ้นแล้ว แต่ตรง Conversion logic ยังเหมือนเดิม ขอบคุณ nOBITa3001 สำหรับ PR แจ่ม ๆ ครับ
ping back: http://www.chonla.com/convert-utf8-to-tis620-back-and-forth-using-dotnet-core/