String

public struct String { /* private fields */ }

A UTF-8 encoded, dynamically sized string with copy-on-write semantics.

String is the standard text type. The bytes are always valid UTF-8. Storage is shared between clones via an RcBox; mutating a String whose storage is referenced elsewhere triggers a copy. Three different views (bytes, chars, graphemes) plus a lines view expose different units of iteration over the same buffer.

Examples

var s = "hello"; s.append(", world"); s.byteCount; // 12 s.contains(","); // true for line in "a\nb".lines { /* ... */ }

UTF-8

All public mutators preserve UTF-8 validity. The bytes view returns raw UInt8s for hashing and FFI; the chars view decodes code points; the graphemes view applies UAX #29 segmentation for user-perceived characters. Choose the view that matches your unit: byte-level work uses bytes, scalar-level work uses chars, and anything user-visible (cursor movement, truncation) uses graphemes.

Representation

A single CowBox[StringStorage] field. The storage record carries (ptr, len, cap); the empty string uses a null pointer with both counts zero.

Memory Model

Reference-counted, copy-on-write. Cloning is O(1); the first mutation after a shared clone allocates and copies the bytes. The raw byte pointer returned from bytes aliases the live buffer; retain strings, not pointers.

Guarantees

  • Bytes are valid UTF-8 after every public mutator.
  • byteCount, capacity, and isEmpty are O(1); count (code points) is O(n).
  • Clones do not share mutation; s.clone() and s will diverge as soon as either is mutated.

Properties

public var byteCount: Int64 { get }

The number of UTF-8 bytes in the string. O(1).

This is not the character count — see count for that. Pure ASCII strings have byteCount == count.

public var bytes: BytesView { get }

s.bytes — view over the raw UTF-8 bytes. O(1) byte indexing, byte-level iteration. Index via the view's subscripts: s.bytes(i), s.bytes(checked: i), s.bytes(0..<n).

public var capacity: Int64 { get }

The number of bytes the storage buffer can hold without reallocating. O(1).

public var chars: CharsView { get }

s.chars — view over the Unicode code points. O(n) indexing, scalar-level iteration. Index via the view's subscripts: s.chars(i), s.chars(checked: i).

public var graphemes: GraphemesView { get }

s.graphemes — view over user-perceived characters (UAX #29 grapheme clusters). Iterate or count, no random access.

public var isEmpty: Bool { get }

True if the string holds zero bytes. O(1).

public var lines: LinesView { get }

A view over the lines of the string, recognising \n, \r\n, and \r.

Initializers

public init()

Constructs an empty string.

Allocates no buffer; the empty string is represented by a null pointer with zero length and capacity. Required by Defaultable.

Examples

let s = String(); s.isEmpty; // true s.byteCount; // 0
public init(from: CString)

Builds a String by copying the bytes out of cstring, excluding the null terminator.

O(n) — cstring.length walks to the terminator and the byte copy is linear. Empty CStrings (length zero) yield the default empty String without touching the pointer.

Safety

cstring.raw must be valid for at least length readable bytes plus a terminator. The conversion does not free the CString's buffer — caller still owns it.

Examples

let cstr = CString(raw: somePtr); let s = String(from: cstr);
public init[I](from: I) where I: Iterable, I.Item == Char

Builds a string by encoding each character of chars as UTF-8.

Mirrors Array.init(from:) and Set.init(from:) — accepts any Iterable whose Item is Char. Useful for materializing the result of an iterator chain back into a String:

let upper = String(from: "hello".chars.iter().map { it.toUpper() }); // "HELLO"
init(storage: CowBox[StringStorage])

Wraps an existing CowBox[StringStorage] as a new String.

Module-internal — used by clone(), StringBuilder.build(), and other std.text code that constructs strings from raw storage.

public init[S](fromUtf8: S) where S: Slice[UInt8]

Constructs a string from validated UTF-8 bytes, returning null if the input is not valid UTF-8.

Examples

let s = String(fromUtf8: "héllo".bytes); // Some("héllo")
public init[S](fromUtf8Lossy: S) where S: Slice[UInt8]

Constructs a string from bytes, replacing invalid UTF-8 sequences with the Unicode replacement character (U+FFFD).

Examples

let s = String(fromUtf8Lossy: mixedBytes); // invalid bytes become '�'
public init[S](fromUtf8Unchecked: S) where S: Slice[UInt8]

Constructs a string by copying bytes without UTF-8 validation.

Safety

The caller must ensure the bytes are valid UTF-8.

public init(stringLiteral: lang.ptr[lang.i8], lang.i64)

Compiler-emitted constructor for string literals.

Receives a static byte pointer and length, then memcpys into a fresh heap allocation so the resulting String owns its bytes (and can be mutated independently of the literal pool).

Errors

Panics with "String allocation failed" if the system allocator returns null.

public init(capacity: Int64)

Constructs an empty string with at least capacity bytes preallocated.

Useful before a series of appends whose total byte count is known: avoids the geometric-growth reallocations the default constructor would incur. A non-positive capacity is treated as zero.

Errors

Panics with "String allocation failed" if the system allocator returns null.

Examples

var s = String(capacity: 64); s.byteCount; // 0 s.capacity; // 64

Methods

mutating func _appendBytes(Pointer[UInt8], Int64)

Appends n bytes from ptr via memcpy. Internal — caller ensures the bytes preserve UTF-8 validity.

Safety

ptr must reference at least n valid UTF-8 bytes that, when concatenated to the current buffer, yield valid UTF-8.

public mutating func append[__opaque_0](__opaque_0) where __opaque_0: Str

Appends other's bytes to this string. COW.

Triggers a copy if storage is shared. Empty appends are a fast no-op.

Examples

var s = "hello"; s.append(", world"); s; // "hello, world"
public mutating func append(char: Char)

Appends a single code point, encoding it as UTF-8.

Sizes the buffer for the encoded length (1–4 bytes) before writing.

Examples

var s = "h"; s.append(char: 'i'); s.append(char: '\u{1F600}'); s; // "hi😀"
internal mutating func appendByte(UInt8)

Appends a raw byte. Internal — caller ensures UTF-8 validity.

Do not use to append ASCII characters: prefer appendChar(c) or append(other). This exists only for low-level UTF-8 plumbing inside the stdlib (e.g. an encoder that already produced bytes).

public mutating func clear()

Truncates the string to length zero, keeping the allocated buffer.

Capacity is unchanged, so this is the right primitive for reusing a buffer in a hot loop.

static func fromBytesUnchecked(Pointer[UInt8], Int64) -> String

Internal helper: copies count bytes from ptr without validation.

static func fromRawBytes(lang.ptr[lang.i8], Int64) -> String

Internal helper: copies count bytes from a raw lang.ptr[lang.i8].

public mutating func lowercase()

Replaces this string with its lowercase form using full Unicode case mapping.

public mutating func lowercaseAscii()

Lowercases ASCII letters in place; non-ASCII bytes are left untouched.

Cheap byte-level scan with no Unicode tables. For locale- independent Unicode case folding, use lowercase.

Examples

var s = "HéLLO"; s.lowercaseAscii(); s; // "héllo" — only ASCII letters touched
public mutating func replace(String, with: String)

Replaces every occurrence of pattern with replacement, in place.

internal func substringBytes(from: Int64, to: Int64) -> String

Internal substring by byte range. Returns empty for invalid ranges.

Do not use for per-character slicing in a loop — each call copies end - start bytes, so walking the string yields O(N²) behaviour. For iteration, use decodeUtf8 with a running byte offset, or the chars() / bytes() views.

public func toCString() -> CString

Allocates a fresh null-terminated copy of this string and returns it as a CString.

Sizes the buffer to byteCount + 1, copies the source bytes via memcpy, and writes the trailing \0. The caller takes ownership and must release the buffer with cstr.free().

Safety

The returned CString aliases freshly allocated memory; do not pass it to a C function that takes ownership of the pointer (it will then be double-freed) and do not forget to free it.

Examples

let cstr = "Hello, C!".toCString(); puts(cstr); cstr.free();
public mutating func trim()

Removes leading and trailing ASCII whitespace in place.

Recognises the same whitespace set as Char.isWhitespace: space, tab, LF, CR, form feed. For Unicode-aware trimming, use the (where:) overloads with a custom predicate. Non-mutating mirrors live under trimmed*.

Examples

var s = " hi "; s.trim(); s; // "hi"
public mutating func trim(where: (Char) -> Bool)

Removes leading and trailing code points matching predicate, in place.

Examples

var s = "***hi***"; s.trim { (c) in c == '*' }; s; // "hi"
public mutating func trimEnd()

Removes trailing ASCII whitespace in place.

public mutating func trimEnd(where: (Char) -> Bool)

Removes trailing code points matching predicate, in place.

public mutating func trimStart()

Removes leading ASCII whitespace in place.

public mutating func trimStart(where: (Char) -> Bool)

Removes leading code points matching predicate, in place.

public mutating func uppercase()

Replaces this string with its uppercase form using full Unicode case mapping.

Locale-independent. Handles multi-character expansions — e.g. German ßSS.

public mutating func uppercaseAscii()

Uppercases ASCII letters in place; non-ASCII bytes are left untouched.

ImplementsStr

Properties

public var byteCount: Int64 { get }

Number of UTF-8 bytes. O(1).

Examples

"hello".byteCount; // 5 "\u{00E9}".byteCount; // 2 (é is two UTF-8 bytes)
public var bytes: BytesView { get }

View over the raw UTF-8 bytes.

Examples

"hi".bytes.count; // 2
public var chars: CharsView { get }

View over Unicode code points.

Examples

"caf\u{00E9}".chars.count; // 4
public var graphemes: GraphemesView { get }

View over grapheme clusters (user-perceived characters).

Examples

"caf\u{00E9}".graphemes.count; // 4
public var isEmpty: Bool { get }

True when the string contains no bytes.

Examples

"".isEmpty; // true "hello".isEmpty; // false
public var lines: LinesView { get }

View over lines, recognising \n, \r\n, and \r.

Examples

"a\nb\nc".lines.count; // 3

Methods

public func asByteSlice() -> ArraySlice[UInt8]

Returns a non-owning ArraySlice[UInt8] view over this string's raw UTF-8 bytes — no copy, no allocation. The slice borrows the live string buffer, so it must not outlive the string (or any mutation of it). O(1).

Use this to hand the bytes to a sink (a socket, a hasher, an FFI call) without materializing an Array[UInt8] via toBytes().

Examples

let bytes = "Hi".asByteSlice(); bytes.count; // 2
public func asSlice() -> StringSlice

Returns a StringSlice covering this string's entire buffer. Shares storage via refcount — zero-copy.

public func caseFolded() -> String

Returns a new string with Unicode case folding applied to each code point.

Case folding maps characters to a canonical form suitable for case-insensitive comparison. Currently single-char folds only (e.g. Aa); multi-char expansions like ßss are not yet supported.

Examples

"Hello".caseFolded(); // "hello"
public func compare(Self) -> Ordering

Lexicographic byte-wise comparison.

Returns Less / Equal / Greater according to the first differing byte; if one string is a prefix of the other, the shorter is less.

Examples

"abc".compare("abd"); // Less "abc".compare("ab"); // Greater
public func contains(String) -> Bool

Returns true if substring appears anywhere in this string.

Examples

"hello world".contains(substring: "world"); // true "hello world".contains(substring: "xyz"); // false
public func ends(with: String) -> Bool

Returns true if this string ends with suffix.

Empty suffix always returns true. Comparison is byte-wise.

Examples

"hello".ends(with: "llo"); // true "hello".ends(with: "xyz"); // false
public func equalsCaseInsensitive(String) -> Bool

Compares two strings for equality after Unicode case folding.

Folds each string to its case-folded form and compares the results byte-wise. Not normalization-aware — é (U+00E9) and e\u{0301} are still considered different.

Examples

"Hello".equalsCaseInsensitive("HELLO"); // true "Hello".equalsCaseInsensitive("World"); // false
public func equalsIgnoreAsciiCase[__opaque_0](__opaque_0) -> Bool where __opaque_0: Str

ASCII case-insensitive equality — folds only AZaz; bytes >= 0x80 must match exactly.

Allocates nothing: it compares the raw UTF-8 bytes in place behind a length fast-path, so it is far cheaper than equalsCaseInsensitive, which builds two Unicode-folded Strings. Use it for ASCII tokens such as HTTP header names, where Unicode folding is unnecessary.

Examples

"Content-Type".equalsIgnoreAsciiCase("content-type"); // true "Content-Type".equalsIgnoreAsciiCase("Host"); // false
public func firstIndex(of: String) -> ByteIndex?

Returns the byte index of the first occurrence of substring, or None if not found.

The empty substring matches at the start. Uses memmem for efficient byte-level search.

Examples

"hello world".firstIndex(of: "world"); // Some(ByteIndex(6)) "hello world".firstIndex(of: "xyz"); // None
public func format(into: mutating StringBuilder, FormatOptions)

Formats the string using the given options.

Examples

"hi".format(FormatOptions(width: 5)); // "hi "
public func hash[H](into: mutating H) where H: Hasher

Hashes the byte content into hasher.

public func isEqual(to: Self) -> Bool

Returns true if both strings have the same byte sequence.

Pure byte-wise equality — not normalization-aware. For case-insensitive comparison, see equalsCaseInsensitive.

Examples

"abc".isEqual(to: "abc"); // true "abc".isEqual(to: "ABC"); // false
public func iter() -> CharsIterator

Returns a CharsIterator over the code points.

Required by Iterable. Each call returns a fresh iterator; the source is reusable.

Examples

for c in "abc" { ... } // iterates 'a', 'b', 'c'
public func lastIndex(of: String) -> ByteIndex?

Returns the byte index of the last occurrence of substring, or None if not found.

Scans from the left using repeated memmem calls, keeping the last match position.

Examples

"abcabc".lastIndex(of: "abc"); // Some(ByteIndex(3)) "abcabc".lastIndex(of: "xyz"); // None
public func lowercased() -> String

Returns the lowercase form using full Unicode case mapping.

Locale-independent. Handles multi-character expansions (e.g. Turkish dotted I). All-ASCII strings with no uppercase letters short-circuit to toOwned() (no per-char decode).

Examples

"Hello".lowercased(); // "hello" "\u{0130}".lowercased(); // "i\u{0307}"
public func lowercasedAscii() -> String

Returns a copy with only ASCII letters lowercased; non-ASCII bytes pass through unchanged.

Cheap byte-level scan with no Unicode tables. For full Unicode case mapping, use lowercased().

Examples

"H\u{00E9}LLO".lowercasedAscii(); // "h\u{00E9}llo"
public func pad(leading: Int64, with: Char) -> String

Returns the string padded at the start with char so the total code-point count is at least length.

If the string is already at least length code points long, returns a copy unchanged.

Examples

"42".pad(leading: 5, with: '0'); // "00042"
public func repeated(Int64) -> String

Returns this string concatenated with itself count times.

Non-positive count returns the empty string. Pre-allocates the result buffer for the exact final length.

Examples

"ab".repeated(3); // "ababab" "ab".repeated(0); // ""
public func replaced(String, with: String) -> String

Returns a copy with every occurrence of pattern replaced by replacement.

Empty pattern is a no-op (returns a copy). Searches greedily from the left and skips past each replacement so substituted text is not re-matched.

Examples

"hello world".replaced("o", with: "0"); // "hell0 w0rld" "abcabc".replaced("ab", with: "ABCD"); // "ABCDcABCDc"
public func split(String) -> SplitView

Returns a lazy view that splits on separator, yielding zero-copy StringSlice segments.

The empty separator is special-cased to split per code point. Adjacent separators produce empty segments.

Examples

"a,b,c".split(",").collect(); // ["a", "b", "c"] "a,,b".split(",").count; // 3 (empty segment preserved)
public func starts(with: String) -> Bool

Returns true if this string starts with prefix.

Empty prefix always returns true. Comparison is byte-wise.

Examples

"hello".starts(with: "hel"); // true "hello".starts(with: "xyz"); // false
public func titlecased() -> String

Returns the titlecase form using full Unicode case mapping.

Word boundaries are detected by Char.isWhitespace; the first non-space character of each run is titlecased and the rest lowercased.

Examples

"hello world".titlecased(); // "Hello World" "FOO BAR".titlecased(); // "Foo Bar"
public func toBytes() -> Array[UInt8]

Copies this string's raw UTF-8 bytes into a new Array[UInt8].

Single bulk copy of the whole byte range (one buffer clone + one memcpy-style loop), so it is O(n) — unlike appending byte by byte, where each COW write re-clones the whole buffer and the total cost is O(n²).

Examples

"Hi".toBytes().count; // 2 "Hi".toBytes()(0); // 72 ('H')
public func toOwned() -> String

Copies this string's bytes into a new independent String.

For String, this is equivalent to clone(). For StringSlice, it copies only the slice's bytes, releasing the reference to the source buffer.

Examples

let slice = "hello world".asSlice(); let owned = slice.toOwned(); // independent copy
public func trimmed() -> StringSlice

Returns a zero-copy slice with leading and trailing ASCII whitespace removed.

Whitespace characters: space (' '), tab ('\t'), newline ('\n'), carriage return ('\r'), and form feed ('\x0C'). The returned StringSlice shares the source buffer — no allocation occurs.

Examples

" hello ".trimmed().toOwned(); // "hello" "\t\n".trimmed().isEmpty; // true
public func trimmedEnd() -> StringSlice

Returns a zero-copy slice with trailing whitespace removed.

See trimmed() for the whitespace set. Leading whitespace is preserved.

Examples

" hello ".trimmedEnd().toOwned(); // " hello"
public func trimmedStart() -> StringSlice

Returns a zero-copy slice with leading whitespace removed.

See trimmed() for the whitespace set. Trailing whitespace is preserved.

Examples

" hello ".trimmedStart().toOwned(); // "hello "
public func uppercased() -> String

Returns the uppercase form using full Unicode case mapping.

Locale-independent. Handles multi-character expansions (e.g. ßSS). All-ASCII strings with no lowercase letters short-circuit to toOwned().

Examples

"hello".uppercased(); // "HELLO" "stra\u{00DF}e".uppercased(); // "STRASSE"
public func uppercasedAscii() -> String

Returns a copy with only ASCII letters uppercased; non-ASCII bytes pass through unchanged.

Cheap byte-level scan with no Unicode tables. For full Unicode case mapping, use uppercased().

Examples

"h\u{00E9}llo".uppercasedAscii(); // "H\u{00E9}LLO"

ImplementsIterable

Associated Types

type Item = Char

The element type yielded by iteration — always Char.

type TargetIterator = CharsIterator

The iterator type returned by iter().

Methods

public func iter() -> CharsIterator

Returns a CharsIterator over the code points starting at byte 0.

Required by Iterable. Each call returns a fresh iterator; the string itself is reusable.

ImplementsEquatable

Associated Types

type Output = Bool

Methods

public func equal(to: Self) -> Bool

Bridges Equal.equal(to:) to Equatable.isEqual(to:).

public func isEqual(to: String) -> Bool

Returns true if both strings have the same byte sequence.

Pure byte-wise equality — not normalization-aware. For case-insensitive comparison, see equalsCaseInsensitive.

Examples

"abc".isEqual(to: "abc"); // true "abc".isEqual(to: "ABC"); // false
public func notEqual(to: Self) -> Bool

Default !=: delegates to == so there's a single source of truth.

ImplementsMatchable

Methods

public func matches(String) -> Bool

Pattern-match form of isEqual: each case "literal" => arm dispatches through here. Cost is O(len) per arm because the compiler emits one call per literal — past a handful of arms, E316 will suggest an if/else if chain instead.

ImplementsComparable

Associated Types

type Output = Bool

Methods

public func compare(String) -> Ordering

Lexicographic byte-wise comparison.

Returns Less / Equal / Greater according to the first differing byte; if one string is a prefix of the other, the shorter is less. Byte order coincides with code-point order because UTF-8 is order-preserving — this is not the same as locale-aware collation.

Examples

"abc".compare("abd"); // Less "abc".compare("ab"); // Greater "abc".compare("abc"); // Equal
public func greaterThan(Self) -> Bool

> derived from compare.

public func greaterThanOrEqual(Self) -> Bool

>= derived from compare.

public func isAtLeast(Self) -> Bool

start.. lower-bound check, derived from compare.

public func isAtMost(Self) -> Bool

..=end upper-bound check, derived from compare.

public func isBelow(Self) -> Bool

..<end upper-bound check, derived from compare.

public func lessThan(Self) -> Bool

< derived from compare.

public func lessThanOrEqual(Self) -> Bool

<= derived from compare.

ImplementsCloneable

Methods

public func clone() -> String

Returns a shallow clone — storage is shared until either side mutates.

O(1). Mutation triggers a deep copy via CowBox.write().

ImplementsFormattable

Methods

public func format(into: mutating StringBuilder, FormatOptions)

Renders this string under the supplied FormatOptions.

Honours width, alignment, and fill. precision / radix / floatStyle / sign are ignored — they don't apply to strings. Aligned padding is measured in code points, not bytes, so multi-byte characters count as one column for alignment purposes (display width still depends on font).

Examples

var opts = FormatOptions(); opts.width = .Some(10); opts.alignment = .Left; "test".format(opts); // "test " opts.alignment = .Right; "test".format(opts); // " test" opts.alignment = .Center; "test".format(opts); // " test "
public func formatted(FormatOptions) -> String

Returns this value rendered as a String.

Convenience wrapper: creates a StringBuilder, calls format(into:), and returns the built string. Uses a distinct name to avoid overload-resolution ambiguity with format(into:).

ImplementsAddable

Properties

public static var zero: String { get }

The additive identity for strings — the empty string "".

Associated Types

type Output = String

The output type of + (concatenation) — always String.

Methods

public consuming func add(consuming String) -> String

Returns the concatenation self + other. Required by Addable. When self is uniquely owned (refcount 1), appends in place — no allocation. Otherwise builds a fresh string with both halves.

ImplementsExpressibleByStringLiteral

Initializers

init(stringLiteral: lang.ptr[lang.i8], lang.i64)

Builds an instance from a string literal.

ImplementsHashable

Methods

public func hash[H](into: mutating H) where H: Hasher

Hashes the raw byte sequence into the supplied hasher.

Sends the whole buffer in a single write so the hasher gets to choose how to consume it.

ImplementsDefaultable

Initializers

init()

Builds the default-valued instance.

ImplementsConvertible

Initializers

init(from: From)

Creates an instance from value.

Defined in lang/std/text/string.ks