Skip to content

Strings

This content is for v0.7. Switch to the latest version for up-to-date documentation.

Strings are delimited by double quotes.

let greeting = "Hello, World!";
let empty = "";

Use a backslash to insert special characters.

SequenceCharacter
\"Double quote
\\Backslash
\nNewline
\rCarriage return
\tTab
// Quoted strings
let msg = "She said \"hello\"";
// Backslash in paths
let path = "C:\\Users\\music\\samples";
// Multiline output
PRINT "line one\nline two\nline three";
// Tab-separated columns
PRINT "Track\tNote\tVelocity";
PRINT "1\tC4\t100";

Use + to join strings.

"RESONON" + " " + "Language"; // "RESONON Language"
// Building strings in loops
let result = "";
for i in range(5) {
result += "* ";
}
PRINT result; // "* * * * * "

Building note names from parts:

let roots = #["C", "D", "E", "F", "G", "A", "B"];
let octave = "4";
for root in roots {
PRINT root + octave; // "C4", "D4", ...
}

Prefix a string with f to interpolate expressions inside {...}.

let name = "RESONON";
let version = 1;
PRINT f"Welcome to {name} v{version}!";
// Any expression works inside braces
PRINT f"2 + 2 = {2 + 2}";
// Method calls
let lang = "resonon";
PRINT f"uppercase: {lang.uppercase()}";
// Literal braces with {{ and }}
PRINT f"Literal braces: {{like this}}";

Format strings are useful for building readable output:

fn describe(item, count) {
f"{count}x {item}"
}
PRINT describe("kick", 4); // "4x kick"
PRINT describe("snare", 2); // "2x snare"

Any valid expression works inside {...}, including ternary-style if/else, array access, and method chains.

let vel = 100;
PRINT f"Dynamics: {if vel > 80 { "loud" } else { "soft" }}";
let notes = #["C4", "E4", "G4"];
PRINT f"Root: {notes[0]}";
let raw = " hello ";
PRINT f"Trimmed: {raw.trim().uppercase()}";

String literals work inside f-string expression blocks.

let items = #["kick", "snare", "hat"];
PRINT f"Count: {items.iter().count()}";
PRINT f"Joined: {items[0] + " & " + items[1]}";

Strings are immutable. Every method returns a new string — the original is never modified.

let original = "Hello";
let upper = original.uppercase();
PRINT original; // "Hello" — unchanged
PRINT upper; // "HELLO"

Methods are called with dot syntax and always return a new value.

MethodDescriptionExample
.uppercase()All characters to upper case"hello".uppercase()"HELLO"
.lowercase()All characters to lower case"HELLO".lowercase()"hello"
.trim()Remove leading/trailing whitespace" hi ".trim()"hi"
.contains(sub)Check if substring exists"hello".contains("ell")true
.starts_with(prefix)Check prefix"hello".starts_with("he")true
.ends_with(suffix)Check suffix"hello".ends_with("lo")true
.replace(old, new)Replace all occurrences"aabb".replace("a", "x")"xxbb"
.substring(start, end)Extract a sub-string"hello".substring(1, 4)"ell"
.split(sep)Split into an array"a,b,c".split(",")["a","b","c"]
.length()Number of characters"hello".length()5
.iter()Character iterator"abc".iter().collect()["a","b","c"]

Replaces all occurrences of a substring.

let pattern = "x-x-x-x-";
pattern.replace("x", "kick"); // "kick-kick-kick-kick-"
// Remove characters by replacing with empty string
"C#4".replace("#", ""); // "C4"

Splits a string into an array at each occurrence of the separator.

let csv = "kick,snare,hat,tom";
let drums = csv.split(",");
PRINT drums; // ["kick", "snare", "hat", "tom"]
PRINT drums[0]; // "kick"
// Split on whitespace
"C4 E4 G4".split(" "); // ["C4", "E4", "G4"]

Extracts characters from start (inclusive) to end (exclusive). Indices are clamped to the string length.

"hello".substring(0, 1); // "h"
"hello".substring(1, 4); // "ell"
// Out-of-range end is clamped
"hello".substring(3, 100); // "lo"

Removes leading and trailing whitespace (spaces, tabs, newlines).

" spaced out ".trim(); // "spaced out"
"\t\ttabbed\n".trim(); // "tabbed"

Test whether a string includes, begins with, or ends with a given substring. All three return true or false.

let port = "IAC Driver Bus 1";
port.contains("Driver"); // true
port.starts_with("IAC"); // true
port.ends_with("Bus 2"); // false
// Filter notes by accidental
let notes = #["C4", "C#4", "D4", "Eb4"];
for n in notes {
if n.contains("#") || n.contains("b") {
PRINT f"{n} is an accidental";
}
}

Because every method returns a new string, calls can be chained:

let messy = " HELLO world ";
messy.trim().lowercase(); // "hello world"
let portName = "IAC Driver Bus 1";
let search = "iac driver";
if portName.lowercase().contains(search.lowercase()) {
PRINT "Match found!";
}

Strings are not directly iterable. Call .iter() to get a character iterator for use with for-in.

for ch in "RESONON".iter() {
PRINT ch;
}
// R
// E
// S
// O
// N
// O
// N

Collect characters into an array:

let chars = "hello".iter().collect();
PRINT chars; // ["h", "e", "l", "l", "o"]

.iter() yields single-character strings. The returned iterator supports the same lazy and eager methods as array iterators.

// Filter vowels
let vowels = "resonon".iter()
.filter(fn(ch) { return ch == "e" || ch == "o"; })
.collect();
PRINT vowels; // ["e", "o", "o"]
// Enumerate characters
let pairs = "abc".iter().enumerate().collect();
// [[0, "a"], [1, "b"], [2, "c"]]

See Arrays — Iterators for the full iterator method reference.