การแปลงข้อความของ String class ออกมาเป็นลำดับตัวอักษรของ Unicode (integer Unicode code points) ใน Dart จะมี Runes class ช่วยในเรื่องนี้
ใช้คำสั่ง Runes()
ในการสร้าง โดยระบุความที่ต้องการ
void main() {
var r = Runes('abc');
print(r); // output → (97, 98, 99)
}
จากตัวอย่างข้อความ abc เมื่อแปลงเป็น Runes แล้วจะได้ค่า 97 98 และ 99 ตามลำดับ แล้วตัวเลขพวกนี้มาจากไหน เมื่อลองไปดูในตาราง Unicode จะพบว่า มันคือค่า
อีกวิธีคือใช้คำสั่ง String.runes
เพื่อคืนค่า Runes กลับมาก็ได้เช่นเดียวกัน
void main() {
var r = 'abc'.runes;
print(r); // output → (97, 98, 99)
}
Runes class มีการสืบทอดมากจาก Iterable class ดังนั้นการเข้าถึงสมาชิก จะใช้คำสั่งใน Iterable class ได้ทันที
void main() {
var r = 'abc'.runes;
print(r); // output → (97, 98, 99)
print(r.first); // output → 97
print(r.elementAt(0)); // output → 97
print(r.last); // output → 99
print(r.elementAt(2)); // output → 99
for (int element in r) {
print(element); // output → 97 98 99
}
}
ใน String class จะมีคำสั่ง .codeUnits
ที่ใช้ดึงค่า UTF-16 code units ของ String อยู่แล้ว ถ้าทดสอบโดยกับข้อความทั่วไป พบว่าค่าที่ได้ไม่ได้แตกต่างค่าที่ออกมาจาก Runes Class เลย
const latinString = 'abc';
print(latinString.runes); // (97, 98, 99)
print(latinString.runes.first.toRadixString(16)); // output → 61 (this is U+0061 code for 'a')
for (final item in latinString.codeUnits) {
print(item.toRadixString(10)); // 97 98 99 in decimal
print(item.toRadixString(16)); // 61 62 63 in hexadecimal
}
จากตัวอย่าง จะเห็นว่า ค่าที่ได้จาก .runes
เป็นค่า 97 98 และ 99 ในเลขฐาน 10 หรือ U+0061 U+0062 และ U+0063 ในเลขฐาน 16 ตามลำดับ ค่าเหล่านี้มีค่าเดียวกับค่าที่ได้จาก .codeUnits
ที่เป็นแบบนี้เพราะ String เป็นชุด UTF-16 ถ้าหากตัวอักษรที่เก็บ มีค่าไม่เกิน U+FFFF มันจะเก็บแค่ 1 ช่อง หรือ 1 codeUnit เท่านั้น แต่เมื่อไหร่ที่มันหลุดจากช่วงนี้ มันจะเก็บเป็น 2 ช่อง
หากใช้เก็บภาษาไทย ซึ่งชุดตัวอักษรจะอยู่ในช่วง U+0E00 ถึง U+0E7F จะได้ผลดังนี้
const thaiString = 'ก๒'; // U+0E01 U+0E52
print(thaiString.runes); // → (3585, 3666)
print(thaiString.runes.first.toRadixString(16)); // output → e01 (this is U+0E01 code for 'ก')
for (final item in thaiString.codeUnits) {
print(item.toRadixString(10)); // → 3585 and 3666 in decimal
print(item.toRadixString(16)); // → e01 and e52 in hexadecimal
}
มาลองดูตัวอย่าง หากตัวอักษรชุดตั้งแต่ U+10000 จะเกิดอะไรขึ้น ในตารางชุดอักษร Linear B Syllabary จะเป็นชุดที่เริ่มต้น U+10000
เมื่อลองเขียนคำสั่งสร้างข้อความและดูว่า Dart เก็บค่าเหล่านี้อย่างไร
const SyllabaryString = '\u{10000}';
print(SyllabaryString.runes); // → (65536)
print(SyllabaryString.runes.first.toRadixString(16)); // → 10000 (same as U+10000)
// Surrogate pairs:
for (final item in SyllabaryString.codeUnits) {
print(item.toRadixString(16)); // → d800 dc00
}
จากตัวอย่างจะเห็นว่า เมื่อเก็บ Unicode รหัส U+10000 หากดูค่าใน runes จะแสดงค่าถูกต้อง แต่เมื่อไปดึงค่าใน codeUnits จะเห็นว่า Dart เก็บค่านี้ไว้ 2 ชุดต่อ 1 ตัวอักษรคือ 0xD800
กับ 0xDC00
สรุปว่าตัว Runes class จะช่วยจัดการแปลงการค่าของ String ที่เก็บในแบบ UTF-16 ที่เกิน 1 ชุดขึ้นไป มาเป็นรหัสตามตาราง Unicode ที่ถูกต้อง ดังนั้น หากต้องการอ้างถึงรหัส Unicode ของ String ที่อาจมีตัวอักษรชุดเพิ่มเติม เช่น Emoji Emoticons สัญลักษณ์ทางคณิตศาสตร์ ฯลฯ
สามารถดู Unicode block ทั้งหมดได้ที่ Wikipedia