Dart 5 ๐ฏ String Manipulation, Interpolation, Multiline Literals, and Raw Strings
The previous chapter introduced String as one of Dart’s built-in types. This chapter goes deeper. A String is not just a container for text โ it is a class with dozens of methods for searching, splitting, replacing, trimming, and transforming text. It supports interpolation, which embeds expressions directly in the literal. It supports multiline literals for text that spans multiple lines. And it supports raw strings for cases where escape sequences must be treated literally.
String manipulation is one of the most common tasks in any programming language. Dart’s string API is rich but consistent. Understanding it is the difference between writing code that fights the language and code that uses it naturally.
Key point: Dart strings are immutable. Every method that appears to modify a string actually returns a new string. The original is never changed. This is not a limitation โ it is a design choice that makes strings safe to share, safe to use as map keys, and safe to pass across isolate boundaries. The cost is that building large strings by concatenation is slow, which is why StringBuffer exists.
Why String Manipulation Matters
Almost every application processes text. User input, API responses, log files, configuration values, HTML, JSON โ all of it is string data. The way you manipulate that data determines the clarity, correctness, and performance of your code.
The transformation problem. You receive a string and need to clean it: trim whitespace, change case, remove characters, replace patterns. Dart provides methods for each of these operations. Knowing which method to use avoids manual character-by-character loops.
The interpolation problem. Building strings by concatenation is verbose and error-prone. String interpolation embeds expressions directly in the literal. The compiler handles the conversion. The result is cleaner and easier to read.
The escape problem. Some strings contain characters that have special meaning: backslashes in Windows paths, dollar signs in shell scripts, newlines in JSON. Raw strings treat every character literally. They eliminate the need to escape every backslash.
The performance problem. Dart strings are immutable. Concatenating in a loop creates a new string on every iteration. StringBuffer accumulates content in a buffer and produces the final string once. For any loop that builds a string from many pieces, StringBuffer is the correct tool.
The trade-off. Dart’s string API is comprehensive, but not every method is needed for every task. The most common methods โ length, isEmpty, contains, split, trim, replaceAll, toUpperCase, toLowerCase, substring, indexOf โ cover most cases. The rest are there when the task requires them.
a. String Interpolation and Expression Embedding
String interpolation embeds an expression inside a string. The expression is evaluated, converted to a string if necessary, and inserted at that position.
var name = 'Alice';
var age = 30;
var greeting = 'Hello, $name!'; // Hello, Alice!
var info = 'You are $age years old.'; // You are 30 years old.
The $identifier syntax works for simple identifiers. For more complex expressions, use ${expression}:
var name = 'Alice';
var message = 'Hello, ${name.toUpperCase()}!'; // Hello, ALICE!
var math = 'The sum is ${2 + 3}.'; // The sum is 5.
var nested = 'Nested: ${'inner $name'}'; // Nested: inner Alice
The braces delimit the expression. Anything inside is evaluated as Dart code. The result is converted to a string with toString().
When the expression is a simple identifier, the braces are optional. $name and ${name} are equivalent. But when the identifier is adjacent to other characters that could be mistaken for part of the name, the braces are required:
var file = 'report';
var bad = '$fileport'; // Looks for a variable named "fileport"
var good = '${file}port'; // reportport
The compiler treats $fileport as a reference to a variable called fileport. The braces separate the variable name from the following text.
String interpolation works with any expression, including method calls, arithmetic, and nested interpolation:
var price = 19.99;
var quantity = 3;
var total = 'Total: \$${(price * quantity).toStringAsFixed(2)}';
// Total: $59.97
The \$ escape is needed because the dollar sign is the interpolation character. The toStringAsFixed(2) formats the number with two decimal places.
b. Multiline Literals and Raw Strings
A multiline string spans multiple lines in the source file. Dart provides two ways to write them: triple single quotes and triple double quotes.
var text1 = '''
This is a
multiline string
using triple single quotes.
''';
var text2 = """
This is a
multiline string
using triple double quotes.
""";
Both forms produce identical results. The choice is stylistic. The triple-quoted string preserves everything between the quotes, including newlines and indentation.
The trim() method is commonly used with multiline strings to remove the leading and trailing whitespace that comes from indentation in the source:
var text = '''
Line one
Line two
Line three
'''.trim();
print(text);
// Line one
// Line two
// Line three
Without trim(), the string would start with a newline and the first line of content would be indented by four spaces.
A raw string is prefixed with r. Inside a raw string, backslashes are literal characters. They do not introduce escape sequences.
var normal = 'Line 1\nLine 2'; // Contains a newline
var raw = r'Line 1\nLine 2'; // Contains backslash-n literally
print(normal);
// Line 1
// Line 2
print(raw);
// Line 1\nLine 2
Raw strings are essential for regular expressions and file paths, where backslashes have specific meanings that should not be interpreted by the string parser:
var pattern = r'\d{3}-\d{4}'; // Regex: three digits, hyphen, four digits
var windowsPath = r'C:\Users\Alice\Documents';
Without the r prefix, \d would be interpreted as an escape sequence (which does not exist in Dart, so it would be an error), and \U in the Windows path would also be an error.
A raw string cannot end with a backslash. The backslash would escape the closing quote, and the string would not terminate. The workaround is to use adjacent literals:
// var bad = r'C:\'; // โ Error: unterminated string
var good = r'C:\' '\'; // โ
"C:\"
Raw strings can be multiline. The r prefix and the triple quotes combine:
var raw = r'''
Line 1\nLine 2
Line 3
''';
The \n is literal. The newlines between the triple quotes are actual newlines.
c. Common String Methods
Dart’s String class provides a rich API. The most commonly used methods fall into a few categories.
Length and emptiness. The length property returns the number of UTF-16 code units. The isEmpty and isNotEmpty properties are booleans.
var s = 'hello';
print(s.length); // 5
print(s.isEmpty); // false
print(''.isEmpty); // true
The length counts UTF-16 code units, not characters. A character outside the Basic Multilingual Plane (such as an emoji) is represented by two code units, so length may be larger than the visible character count.
Searching. The contains method checks whether a string contains another string. The startsWith and endsWith methods check the beginning and end. The indexOf and lastIndexOf methods return the position of a substring, or -1 if not found.
var s = 'Hello, world!';
print(s.contains('world')); // true
print(s.startsWith('Hello')); // true
print(s.endsWith('!')); // true
print(s.indexOf('o')); // 4
print(s.lastIndexOf('o')); // 8
print(s.indexOf('xyz')); // -1
Case conversion. The toUpperCase and toLowerCase methods return new strings with the case changed.
var s = 'Hello';
print(s.toUpperCase()); // HELLO
print(s.toLowerCase()); // hello
Trimming. The trim, trimLeft, and trimRight methods remove whitespace from the ends of a string.
var s = ' Hello ';
print(s.trim()); // 'Hello'
print(s.trimLeft()); // 'Hello '
print(s.trimRight()); // ' Hello'
Splitting and joining. The split method divides a string into a list of substrings based on a delimiter. The join method on a list combines the elements into a single string.
var s = 'one,two,three';
var parts = s.split(',');
print(parts); // [one, two, three]
var joined = parts.join(' | ');
print(joined); // one | two | three
The split method accepts a Pattern, which can be a string or a regular expression. The splitMapJoin method combines splitting, transforming, and joining in a single operation.
Replacing. The replaceAll and replaceFirst methods replace occurrences of a pattern with a replacement string.
var s = 'Hello, world!';
print(s.replaceAll('o', '0')); // Hell0, w0rld!
print(s.replaceFirst('o', '0')); // Hell0, world!
Extracting substrings. The substring method returns a portion of the string. The substring(start, end) form returns the characters from start to end (exclusive).
var s = 'Hello, world!';
print(s.substring(0, 5)); // Hello
print(s.substring(7)); // world!
Padding. The padLeft and padRight methods add characters to the beginning or end of a string until it reaches a specified length.
var s = '42';
print(s.padLeft(5, '0')); // 00042
print(s.padRight(5, '*')); // 42***
Character codes. The codeUnitAt and codeUnits methods expose the underlying UTF-16 code units. The runes property exposes the Unicode code points.
var s = 'A';
print(s.codeUnitAt(0)); // 65
var emoji = '๐';
print(emoji.length); // 2 (two code units)
print(emoji.runes.length); // 1 (one code point)
StringBuffer. For building strings from many pieces, StringBuffer is the efficient choice.
var buffer = StringBuffer();
for (var i = 0; i < 1000; i++) {
buffer.write('$i ');
}
var result = buffer.toString();
The StringBuffer accumulates content in a growable buffer. The toString() call produces the final string. This is much faster than repeated + concatenation, which creates a new string on every iteration.
Complete Example Session
This session demonstrates interpolation, multiline literals, raw strings, and the common string methods.
void main() {
// ============================================
// PART 1: STRING INTERPOLATION
// ============================================
var name = 'Alice';
var age = 30;
print('Hello, $name!'); // Hello, Alice!
print('You are $age years old.'); // You are 30 years old.
print('Uppercase: ${name.toUpperCase()}'); // Uppercase: ALICE
print('Math: ${2 + 3}'); // Math: 5
print('Nested: ${'inner $name'}'); // Nested: inner Alice
// Braces needed for disambiguation
var file = 'report';
print('${file}port'); // reportport
print('$file' 'port'); // reportport
// ============================================
// PART 2: MULTILINE LITERALS
// ============================================
var multiline = '''
Line one
Line two
Line three''';
print(multiline);
// With trim
var trimmed = '''
Indented line one
Indented line two
'''.trim();
print(trimmed);
// ============================================
// PART 3: RAW STRINGS
// ============================================
var regex = r'\d{3}-\d{4}';
print(regex); // \d{3}-\d{4}
var windowsPath = r'C:\Users\Alice\Documents';
print(windowsPath); // C:\Users\Alice\Documents
var newlineLiteral = r'Line 1\nLine 2';
print(newlineLiteral); // Line 1\nLine 2
// ============================================
// PART 4: LENGTH AND EMPTINESS
// ============================================
var s = 'hello';
print(s.length); // 5
print(s.isEmpty); // false
print(''.isEmpty); // true
// ============================================
// PART 5: SEARCHING
// ============================================
var text = 'Hello, world!';
print(text.contains('world')); // true
print(text.startsWith('Hello')); // true
print(text.endsWith('!')); // true
print(text.indexOf('o')); // 4
print(text.lastIndexOf('o')); // 8
print(text.indexOf('xyz')); // -1
// ============================================
// PART 6: CASE AND TRIMMING
// ============================================
print('Hello'.toUpperCase()); // HELLO
print('Hello'.toLowerCase()); // hello
print(' Hello '.trim()); // Hello
print(' Hello '.trimLeft()); // Hello
print(' Hello '.trimRight()); // Hello
// ============================================
// PART 7: SPLITTING AND JOINING
// ============================================
var csv = 'one,two,three';
var parts = csv.split(',');
print(parts); // [one, two, three]
print(parts.join(' | ')); // one | two | three
// Split by regular expression
var spaced = 'one two three';
var words = spaced.split(RegExp(r'\s+'));
print(words); // [one, two, three]
// ============================================
// PART 8: REPLACING AND SUBSTRINGS
// ============================================
print('Hello, world!'.replaceAll('o', '0')); // Hell0, w0rld!
print('Hello, world!'.replaceFirst('o', '0')); // Hell0, world!
print('Hello, world!'.substring(0, 5)); // Hello
print('Hello, world!'.substring(7)); // world!
// ============================================
// PART 9: PADDING AND CHARACTER CODES
// ============================================
print('42'.padLeft(5, '0')); // 00042
print('42'.padRight(5, '*')); // 42***
print('A'.codeUnitAt(0)); // 65
print('๐'.length); // 2
print('๐'.runes.length); // 1
// ============================================
// PART 10: STRINGBUFFER
// ============================================
var buffer = StringBuffer();
for (var i = 0; i < 5; i++) {
buffer.write('Item $i ');
}
print(buffer.toString()); // Item 0 Item 1 Item 2 Item 3 Item 4
}
The ten parts cover string interpolation, multiline literals, raw strings, length and emptiness, searching, case and trimming, splitting and joining, replacing and substrings, padding and character codes, and StringBuffer.
Quick Reference
The Interpolation Syntax
| Syntax | Purpose | Example |
|---|---|---|
$identifier | Simple variable | 'Hello, $name' |
${expression} | Complex expression | '${user.name}' |
\${...} | Literal dollar sign | 'Cost: \$5' |
The String Literal Forms
| Form | Syntax | Escape Sequences |
|---|---|---|
| Single quotes | '...' | Processed |
| Double quotes | "..." | Processed |
| Triple quotes | '''...''' | Processed |
| Raw single | r'...' | Literal |
| Raw triple | r'''...''' | Literal |
The Common Methods
| Method | Purpose |
|---|---|
contains() | Check for substring |
startsWith() | Check prefix |
endsWith() | Check suffix |
indexOf() | Find position |
toUpperCase() | Convert to uppercase |
toLowerCase() | Convert to lowercase |
trim() | Remove whitespace |
split() | Divide into parts |
replaceAll() | Replace all occurrences |
substring() | Extract portion |
padLeft() / padRight() | Add padding |
The StringBuffer Methods
| Method | Purpose |
|---|---|
write() | Append a value |
writeln() | Append a value with newline |
writeAll() | Append multiple values |
toString() | Produce the final string |
clear() | Reset the buffer |
Best Practices
โ Do This:
// Use interpolation for building strings
var greeting = 'Hello, $name!'; // โ
// Use braces for disambiguation
var result = '${file}port'; // โ
// Use raw strings for regex and paths
var pattern = r'\d+'; // โ
// Use trim() with multiline literals
var text = '''
Line one
'''.trim(); // โ
// Use StringBuffer for loop concatenation
var buffer = StringBuffer();
for (var item in items) buffer.write(item); // โ
// Use runes for character counting
var length = emoji.runes.length; // โ
โ Don’t Do This:
// Don't concatenate in a loop with +
var result = '';
for (var i = 0; i < 1000; i++) {
result += '$i'; // โ ๏ธ Creates 1000 intermediate strings
}
// Don't forget the r prefix for paths
var path = 'C:\Users\name'; // โ \U is an invalid escape
// Don't assume length equals character count
var emoji = '๐';
print(emoji.length); // โ ๏ธ 2, not 1
// Don't assume string methods modify the original
var s = 'hello';
s.toUpperCase(); // โ ๏ธ Returns a new string, s is unchanged
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
$fileport empty | Shell reads fileport as variable | Use ${file}port |
| Raw string error | Backslash before quote | Use adjacent literals |
| Unicode length wrong | Counting UTF-16 units | Use runes.length |
| Slow loop concatenation | Immutable strings | Use StringBuffer |
| Escape sequence error | Missing r prefix | Add r prefix |
Real-World Examples
1. Greeting
var greeting = 'Hello, $name!';
2. Disambiguation
var result = '${file}port';
3. Multiline
var text = '''
Line one
Line two
''';
4. Raw Regex
var pattern = r'\d{3}-\d{4}';
5. Raw Path
var path = r'C:\Users\Alice';
6. Search
if (text.contains('error')) { ... }
7. Split and Join
var parts = csv.split(',');
var joined = parts.join(' | ');
8. Replace
var cleaned = input.replaceAll(RegExp(r'\s+'), ' ');
9. Padding
var id = '42'.padLeft(5, '0');
10. StringBuffer
var buffer = StringBuffer();
for (var item in items) buffer.writeln(item);
Visual
String Interpolation
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 'Hello, $name!' โ
โ โ โ
โ โโ $name โ name.toString() โ
โ โ
โ 'Total: ${price * qty}' โ
โ โ โ
โ โโ ${...} โ evaluate, then toString() โ
โ โ
โ '${file}port' โ
โ โ โ
โ โโ braces separate variable from text โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Raw vs Normal Strings
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ NORMAL: 'Line 1\nLine 2' โ
โ โ Line 1 โ
โ Line 2 โ
โ โ
โ RAW: r'Line 1\nLine 2' โ
โ โ Line 1\nLine 2 โ
โ โ
โ The r prefix disables all escape sequences. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
StringBuffer vs Concatenation
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CONCATENATION: โ
โ var s = ''; โ
โ for (...) s += item; โ
โ โ creates N intermediate strings โ
โ โ
โ STRINGBUFFER: โ
โ var buf = StringBuffer(); โ
โ for (...) buf.write(item); โ
โ โ accumulates in a growable buffer โ
โ โ produces one final string โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Unicode Length
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ '๐' โ
โ length โ 2 (UTF-16 code units) โ
โ runes.length โ 1 (Unicode code points) โ
โ โ
โ For character counting, use runes. โ
โ For byte-level operations, use codeUnits. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Interpolation | $name or ${expression} |
| Braces needed | When adjacent to text |
| Multiline | '''...''' or """...""" |
| Raw string | r'...' or r'''...''' |
| Length | UTF-16 code units |
| Runes | Unicode code points |
| Concatenation | Adjacent literals or + |
| Efficient building | StringBuffer |
| Common methods | contains, split, trim, replaceAll, substring |
Key takeaways:
- String interpolation embeds expressions in strings. Use
$identifierfor simple identifiers and${expression}for complex expressions. The braces are required when the variable is adjacent to text that could be mistaken for part of the name. - Multiline strings use triple quotes. The
'''and"""forms preserve newlines and indentation. Usetrim()to remove the leading and trailing whitespace from source indentation. - Raw strings disable escape sequences. The
rprefix makes backslashes literal. Raw strings are essential for regular expressions and Windows file paths. - Strings are immutable. Every method returns a new string. The original is never modified. This makes strings safe to share and safe to use as map keys.
- The
lengthproperty counts UTF-16 code units. For characters outside the Basic Multilingual Plane, such as emoji,lengthis larger than the visible character count. Userunes.lengthfor Unicode code point counting. StringBufferis the efficient way to build strings in loops. Repeated+concatenation creates a new string on every iteration.StringBufferaccumulates content in a growable buffer and produces the final string once.- The
splitmethod accepts aPattern. A string delimiter or a regular expression can be used. Thejoinmethod on the resulting list combines the parts back into a single string.
Remember: Dart strings are immutable sequences of UTF-16 code units with a rich API. Interpolation embeds expressions. Multiline literals span lines. Raw strings treat every character literally. The StringBuffer builds strings efficiently. The length property counts code units, not characters. Understanding these rules prevents the most common mistakes and makes string handling natural.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!