Skip to content

Strings

Zeus provides a first-class string type for working with text. Strings are immutable sequences of UTF-8 encoded bytes.

String Literals

String literals are enclosed in double quotes and create string objects:

let greeting = "Hello, Zeus!";
let emoji = "Welcome 👋";
let japanese = "こんにちは";

String literals fully support UTF-8, including multi-byte characters and emojis.

Escape Sequences

String literals support escape sequences for special characters:

EscapeCharacter
\nNewline
\tTab
\rCarriage return
\\Backslash
\"Double quote
\'Single quote
\0Null character
\eEscape (ESC, 0x1b)
\xHHByte from two hex digits (e.g. \x1b)
console.log("Line 1\nLine 2"); // Two lines
console.log("Col1\tCol2\tCol3"); // Tab-separated
console.log("Say \"Hello\""); // Embedded quotes
console.log("Path: C:\\Users"); // Backslash
console.log("\e[31mred\e[0m"); // ANSI-colored text (see Colors)

Output:

Line 1
Line 2
Col1 Col2 Col3
Say "Hello"
Path: C:\Users

String vs u8[]

Zeus has two ways to work with text:

TypeMutabilityUse Case
stringImmutableText that shouldn’t change
u8[]MutableWhen you need to modify bytes

Creating Strings

// String literal creates an immutable string
let message: string = "Hello";

Converting to Mutable Bytes

When you assign a string to a u8[], Zeus creates a copy of the underlying bytes. This copy is mutable:

let original: string = "Hello";
// Creates a mutable copy of the bytes
let bytes: u8[] = original;
// Modify the copy (original is unchanged)
bytes[0] = 'h';
console.log(original); // "Hello" (unchanged)
// To log bytes, convert back to string
let modified: string = bytes;
console.log(modified); // "hello"

Properties

length

Returns the length of the string in bytes (not characters).

let text = "Hello";
let len = text.length; // 5
let emoji = "👋";
let emojiLen = emoji.length; // 4 (UTF-8 bytes)

Methods

compare

Compares two strings lexicographically (byte-by-byte).

compare(other: string): i8

Returns:

  • -1 if this string comes before other
  • 0 if the strings are equal
  • 1 if this string comes after other
let a = "apple";
let b = "banana";
let c = "apple";
let cmp1 = a.compare(b); // -1 (apple < banana)
let cmp2 = b.compare(a); // 1 (banana > apple)
let cmp3 = a.compare(c); // 0 (apple == apple)

equals

Checks if two strings are equal.

equals(other: string): boolean

Returns: true if the strings have the same bytes, false otherwise.

let a: string = "hello";
let b: string = "hello";
let c: string = "world";
if (a.equals(b)) {
// This executes - strings are equal
}
if (a.equals(c) == false) {
// This executes - strings are different
}

concat

Concatenates two strings and returns a new string.

concat(other: string): string

Returns: A new string containing both strings joined together.

let hello = "Hello";
let world = "World";
let greeting = hello.concat(" ").concat(world);
console.log(greeting); // "Hello World"

Search, slice, transform

These byte-oriented methods mirror JavaScript’s String methods:

slice(start: i32, end: i32): string // JS-style; negative indices count from the end
substring(start: i32, end: i32): string // clamps to 0; swaps if start > end
indexOf(needle: string): i32 // first index, or -1
lastIndexOf(needle: string): i32 // last index, or -1
includes(needle: string): boolean
startsWith(prefix: string): boolean
endsWith(suffix: string): boolean
toUpperCase(): string // ASCII
toLowerCase(): string // ASCII
trim(): string trimStart(): string trimEnd(): string
repeat(count: i32): string
padStart(targetLength: i32, pad: string): string
padEnd(targetLength: i32, pad: string): string
replace(search: string, replacement: string): string // first occurrence (literal)
replaceAll(search: string, replacement: string): string // all occurrences (literal)
charAt(index: i32): string // 1-char string, or "" out of range
charCodeAt(index: i32): i32 // byte value, or -1 out of range
split(separator: string): string[] // "" separator splits into single bytes
let s = "Hello, World";
console.log(s.slice(7, s.length)); // "World"
console.log(s.slice(-5, s.length)); // "World"
console.log(s.toUpperCase()); // "HELLO, WORLD"
console.log(" trim me ".trim()); // "trim me"
console.log("7".padStart(3, "0")); // "007"
console.log("a,b,c".replaceAll(",", "-")); // "a-b-c"
let parts: string[] = "a,b,c".split(","); // ["a", "b", "c"]
console.log(parts.length); // 3

String Operators

Zeus supports operators for string manipulation and comparison:

Concatenation (+)

The + operator concatenates two strings:

let first = "Hello";
let second = "World";
let result = first + " " + second;
console.log(result); // "Hello World"

Equality Operators (== and !=)

Compare strings for equality or inequality:

let a = "hello";
let b = "hello";
let c = "world";
if (a == b) {
console.log("a equals b"); // This executes
}
if (a != c) {
console.log("a not equals c"); // This executes
}

Comparison Operators (<, >, <=, >=)

Compare strings lexicographically (dictionary order):

let apple = "apple";
let banana = "banana";
if (apple < banana) {
console.log("apple comes before banana"); // This executes
}
if (banana > apple) {
console.log("banana comes after apple"); // This executes
}
let a = "hello";
let b = "hello";
if (a <= b) {
console.log("a <= b"); // This executes (they're equal)
}
if (a >= b) {
console.log("a >= b"); // This executes (they're equal)
}

Indexing

You can read individual bytes from a string using indexing:

let greeting: string = "Hello";
let h: u8 = greeting[0]; // 72 ('H')
let e: u8 = greeting[1]; // 101 ('e')
let o: u8 = greeting[4]; // 111 ('o')

Since strings are immutable, you cannot assign to a string index:

let text: string = "Hello";
text[0] = 'h'; // Error: cannot assign to string index: strings are immutable

To modify characters, convert to u8[] first:

let text: string = "Hello";
let bytes: u8[] = text; // Create mutable copy
bytes[0] = 'h'; // Modify the copy
let modified: string = bytes; // "hello"

Implicit Conversions

Zeus supports implicit conversion between string and u8[]:

string → u8[]

Creates a mutable copy of the string’s bytes:

let text: string = "Hello";
let bytes: u8[] = text; // Mutable copy
bytes[0] = 'J'; // Modify the copy

u8[] → string

Creates a new immutable string from the bytes:

let bytes: u8[] = new u8[];
bytes[0] = 'H';
bytes[1] = 'i';
let text: string = bytes; // Creates immutable string "Hi"

Working with Bytes

Since strings are UTF-8 encoded, you can work with individual bytes through u8[]:

let greeting: string = "Hi!";
// Convert to mutable bytes
let bytes: u8[] = greeting;
// Access individual bytes
let h: u8 = bytes[0]; // 72 ('H')
let i: u8 = bytes[1]; // 105 ('i')
let exclaim: u8 = bytes[2]; // 33 ('!')
// Modify bytes
bytes[0] = 'h'; // lowercase
// Convert back to string for output
let modified: string = bytes;
console.log(modified); // "hi!"

UTF-8 Encoding

Strings use UTF-8 encoding, where characters can be 1-4 bytes:

CharacterBytesExample
ASCII1 byte'A' = 65
Extended Latin2 bytes'é'
CJK3 bytes'日'
Emoji4 bytes'👋'
let ascii = "A";
let asciiLen = ascii.length; // 1
let emoji = "👋";
let emojiLen = emoji.length; // 4

Template String Literals

Template string literals use backticks and ${expression} placeholders to embed values inline:

let name = "Zeus";
let count = 3;
let greeting = `Hello, ${name}!`; // "Hello, Zeus!"
let stats = `${name} has ${count} fans`; // "Zeus has 3 fans"
let plain = `no interpolation here`; // "no interpolation here"

Any value can be interpolated — numbers, booleans, objects, and arrays are converted to a string automatically (via their toString, structural reflection for objects/arrays otherwise). The same conversion powers + string concatenation:

class Point { x: i32; constructor(x: i32) { this.x = x; } }
let n = 42;
let p = new Point(7);
let msg = `n=${n}, p=${p}`; // "n=42, p=Point { x: 7 }"
let sum = "value: " + n; // "value: 42"

Future Features

Regular-expression matching (match, regex-based replace/split) is planned once Zeus gains a regex engine.