Strings and Text Processing
Raku was born from a language famous for text processing, and it shows. Whether you need to interpolate variables, slice and dice strings, or perform search-and-replace operations, Raku has you covered with a clean, consistent API. Let us explore everything you need for everyday string work.String Basics
Raku has two kinds of string quoting: single quotes (no interpolation) and double quotes (with interpolation).Double-quoted strings interpolate:my $name = "Raku"; say 'Hello, $name'; # Hello, $name (literal, no interpolation) say "Hello, $name"; # Hello, Raku (variable interpolated)
- Variables:
$scalar,@array,%hash - Code blocks:
{ expression } - Method calls on variables:
$name.uc - Escape sequences:
\n,\t,\\, etc.
my $x = 42; say "The answer is $x"; # The answer is 42 say "Double: { $x * 2 }"; # Double: 84 say "Uppercase: $x.WHAT.gist()"; # Uppercase: (Int) say "Tab\there\nNew line"; # Tab here # New line
Quoting Constructs
Raku provides a flexible quoting system withQ, q, and qq:
You can choose your own delimiters:say Q[No $interpolation at all]; # No $interpolation at all say q[Single-quote $rules]; # Single-quote $rules say qq[Double-quote $rules: {1+1}]; # Double-quote rules: 2
say q|pipes work|; say q{braces too}; say q<angle brackets>; say qq!exclamation marks with $name!;
String Interpolation Deep Dive
Inside double-quoted strings, you can call methods directly on variables:For more complex expressions, use curly braces:my $text = "hello world"; say "Upper: $text.uc()"; # Upper: HELLO WORLD say "Words: $text.words.elems()"; # Words: 2 say "Title: $text.tc()"; # Title: Hello world
my @items = <apple banana cherry>; say "Count: { @items.elems }"; say "Joined: { @items.join(', ') }"; say "First: { @items[0].uc }";
Array and Hash Interpolation
Arrays and hashes interpolate differently:Note: baremy @colors = <red green blue>; say "Colors: @colors[]"; # Colors: red green blue say "Joined: @colors.join(', ')"; # Joined: red, green, blue my %conf = host => "localhost", port => 8080; say "Host: %conf<host>"; # Host: localhost
@colors in a double-quoted string does not interpolate (it is treated as literal text). You need @colors[] or a method call to trigger array interpolation.
Heredocs
For multi-line strings, heredocs are your friend:The indentation of the closingmy $html = q:to/END/; <html> <body> <p>Hello, World!</p> </body> </html> END say $html;
END marker determines how much leading whitespace is stripped. This keeps your heredocs nicely indented in your code.
Interpolating heredocs use qq:to:
my $name = "Raku"; my $year = 2026; my $message = qq:to/END/; Welcome to $name! The year is $year. Math works: { 40 + 2 } END say $message;
String Length and Properties
Themy $str = "Hello, Raku!"; say $str.chars; # 12 (number of characters) say $str.codes; # 12 (number of Unicode codepoints) say $str.bytes; # depends on encoding say $str.encode('utf-8').bytes; # 12 for ASCII text
.chars method is what you will use 99% of the time. Raku handles Unicode correctly, so multi-byte characters count as single characters:
my $emoji = "Hello! 🎉"; say $emoji.chars; # 8 (the emoji counts as 1 character)
Words, Lines, and Characters
Raku makes it easy to break strings apart:my $sentence = "The quick brown fox jumps"; # Split into words say $sentence.words; # (The quick brown fox jumps) say $sentence.words.elems; # 5 say $sentence.words[0]; # The # Split into individual characters say "Raku".comb; # (R a k u) say "Raku".comb.elems; # 4 # Split into lines my $multiline = "line one\nline two\nline three"; say $multiline.lines; # (line one line two line three) say $multiline.lines.elems; # 3
Split and Join
.split breaks a string apart; .join puts it back together:
my $csv = "alice,bob,charlie,diana"; my @names = $csv.split(","); say @names; # [alice bob charlie diana] say @names.join(" | "); # alice | bob | charlie | diana
.split accepts strings, regexes, and limits:
my $data = "one::two::three::four"; say $data.split("::"); # (one two three four) say $data.split("::", 3); # (one two three::four) limit to 3 parts say $data.split(/\d+/); # splits on digit sequences
# Split on multiple delimiters my $mixed = "hello;world,foo:bar"; say $mixed.split(/<[;,:]>/); # (hello world foo bar)
comb: The Flexible Splitter
.comb is like split, but it extracts matching portions instead of splitting on them:
say "Hello World 123".comb(/\d/); # (1 2 3) say "Hello World 123".comb(/\d+/); # (123) say "Hello World 123".comb(/\w+/); # (Hello World 123) # Extract every N characters say "abcdefgh".comb(2); # (ab cd ef gh) say "abcdefgh".comb(3); # (abc def gh)
Index and Substr
Find positions within strings and extract substrings:my $str = "Hello, Raku World!"; say $str.index("Raku"); # 7 (position where "Raku" starts) say $str.index("Python"); # Nil (not found) say $str.index("l"); # 2 (first occurrence) say $str.rindex("l"); # 15 (last occurrence) # Containment check say $str.contains("Raku"); # True say $str.contains("Python"); # False
.substr extracts a portion of the string:
my $str = "Hello, Raku World!"; say $str.substr(7); # Raku World! (from position 7 to end) say $str.substr(7, 4); # Raku (4 characters starting at position 7) say $str.substr(0, 5); # Hello (first 5 characters) say $str.substr(*-6); # orld! (last 6 characters, * counts from end)
String Repetition
Thex operator repeats a string:
This is handy for creating separators, padding, and formatted output:say "ha" x 3; # hahaha say "-" x 40; # ---------------------------------------- say ("Na " x 8) ~ "Batman!"; # Na Na Na Na Na Na Na Na Batman!
sub heading($title) { my $bar = "=" x $title.chars; say $bar; say $title; say $bar; } heading("Chapter One"); # =========== # Chapter One # ===========
Search and Replace with .subst
.subst is Raku's string replacement method:
Themy $str = "Hello World"; say $str.subst("World", "Raku"); # Hello Raku say $str.subst(/\w+/, "Hey"); # Hey World (first match only) say $str.subst(/\w+/, "Hey", :g); # Hey Hey (global replacement)
:g adverb makes it replace all occurrences, not just the first.
Using Captures in Replacement
my $date = "2026-03-13"; say $date.subst(/(\d+) '-' (\d+) '-' (\d+)/, { "$2/$1/$0" }); # 13/03/2026 # Swap first and last words my $str = "Hello Beautiful World"; say $str.subst(/^(\w+) (.*) (\w+)$/, { "$2 $1 $0" });
Case Conversion
my $str = "hello, raku world!"; say $str.uc; # HELLO, RAKU WORLD! (uppercase) say $str.lc; # hello, raku world! (lowercase) say $str.tc; # Hello, raku world! (title case first char) say $str.tclc; # Hello, raku world! (title case first, lower rest) say $str.wordcase; # Hello, Raku World! (capitalize each word)
Trimming Whitespace
my $padded = " hello "; say $padded.trim; # "hello" (both sides) say $padded.trim-leading; # "hello " (left only) say $padded.trim-trailing; # " hello" (right only)
Practical Example: Log Parser
Let us put these tools together in a practical example that parses log lines:Output:#!/usr/bin/env raku my @log-lines = ( "2026-03-13 10:30:15 INFO User alice logged in", "2026-03-13 10:30:22 ERROR Database connection failed", "2026-03-13 10:31:05 INFO User bob logged in", "2026-03-13 10:31:10 WARN Disk space low: 15% remaining", "2026-03-13 10:32:00 ERROR Timeout on API call", ); for @log-lines -> $line { my @parts = $line.split(/\s+/, 4); # split into 4 parts max my $date = @parts[0]; my $time = @parts[1]; my $level = @parts[2]; my $msg = @parts[3]; # Only show errors and warnings next unless $level eq "ERROR" | "WARN"; my $emoji = $level eq "ERROR" ?? "!!!" !! "???"; say "$emoji [$time] $msg"; }
!!! [10:30:22] Database connection failed ??? [10:31:10] Disk space low: 15% remaining !!! [10:32:00] Timeout on API call