What are Runes in Dart?
#dart#runes#unicode#utf-16#string#code-points
Answer
Overview
In Dart, Runes are the Unicode code points of a
text
StringThe Problem: UTF-16 Encoding
A Dart
text
Stringdartvoid main() { final emoji = '๐จ'; // U+1F468 (Man emoji) print(emoji.length); // 2 (two UTF-16 code units!) print(emoji.codeUnits); // [55357, 56424] (surrogate pair) print(emoji.runes.toList()); // [128104] (one Unicode code point: 0x1F468) }
String.runes Property
The
text
runestext
Iterable<int>dartvoid main() { // ASCII characters โ no difference const ascii = 'Dart'; print(ascii.length); // 4 print(ascii.runes.toList()); // [68, 97, 114, 116] print(ascii.codeUnits); // [68, 97, 114, 116] (same!) // Emoji โ runes vs codeUnits differ const emoji = '๐ฏ๐ฅ'; print(emoji.length); // 4 (each emoji = 2 code units) print(emoji.codeUnits.length); // 4 print(emoji.runes.length); // 2 (two actual characters) print(emoji.runes.toList()); // [127919, 128293] }
The Runes Class
text
Runestext
dart:coredartvoid main() { const text = 'Hello ๐'; // Using Runes class directly final runes = Runes(text); for (final rune in runes) { print('U+${rune.toRadixString(16).toUpperCase()} -> ${String.fromCharCode(rune)}'); } // U+48 -> H // U+65 -> e // U+6C -> l // U+6C -> l // U+6F -> o // U+20 -> // U+1F30D -> ๐ }
Creating Strings from Runes
Use
text
String.fromCharCodes()dartvoid main() { // Create string from Unicode code points final heart = String.fromCharCode(0x2764); // โค final dart = String.fromCharCodes([0x44, 0x61, 0x72, 0x74]); // Dart final emoji = String.fromCharCode(0x1F600); // ๐ print(heart); // โค print(dart); // Dart print(emoji); // ๐ // Using rune literals in strings print('I \u2764 Dart'); // I โค Dart print('\u{1F600}'); // ๐ (use {} for > 4 hex digits) }
Practical Use Cases
1. Correctly Counting Characters
dartint characterCount(String text) { // โ Wrong โ counts UTF-16 code units // return text.length; // โ Correct โ counts actual Unicode characters return text.runes.length; } void main() { print(characterCount('Hello')); // 5 print(characterCount('Hello ๐')); // 7 (not 8!) }
2. Safe String Manipulation
dart// โ Wrong โ may split a surrogate pair String wrongTruncate(String s, int maxLength) { return s.substring(0, maxLength); } // โ Correct โ respects Unicode characters String safeTruncate(String s, int maxChars) { final runes = s.runes.toList(); if (runes.length <= maxChars) return s; return String.fromCharCodes(runes.sublist(0, maxChars)); } void main() { const text = '๐จโ๐ฉโ๐งโ๐ฆ Family'; print(safeTruncate(text, 3)); // Safely truncates }
3. Character Validation
dartbool containsEmoji(String text) { return text.runes.any((rune) => rune > 0xFFFF); } void main() { print(containsEmoji('Hello')); // false print(containsEmoji('Hello ๐')); // true }
Runes vs codeUnits vs characters
| Property | Returns | Handles Emojis | Handles Grapheme Clusters |
|---|---|---|---|
text | UTF-16 code unit count | No | No |
text | UTF-16 code units | No | No |
text | Unicode code points | Yes | No |
text | Grapheme clusters | Yes | Yes |
dartimport 'package:characters/characters.dart'; void main() { const family = '๐จโ๐ฉโ๐งโ๐ฆ'; // Family emoji (one visual character) print(family.length); // 11 (many code units) print(family.codeUnits.length); // 11 print(family.runes.length); // 7 (multiple code points joined by ZWJ) print(family.characters.length); // 1 (one grapheme cluster โ ) }
Key Insight: Use
when you need true Unicode code points (not UTF-16 code units). For user-visible character counting (especially with complex emojis), use thetext.runespackage for grapheme cluster support.textcharacters