String
String is a heap-owned, NUL-terminated UTF-8 string. Every method that
indexes says which unit it works in:
Bytein the name → byte semantics. Indexes, lengths and slices count raw bytes. These are O(1), and bytes are the right unit for parsing, protocols and file formats.Charin the name → character semantics. Indexes and counts are Unicode code points decoded from the UTF-8.charAt(1)of"héllo"isU+00E9, not the second byte of its encoding.- No unit in the name → whole-string.
append,trimmed,equals,hasPrefix… treat the string as a value and take no index.
#import "String.xc" // or the Foundation umbrellaOverview
Section titled “Overview”A String owns a growable byte buffer and keeps it NUL-terminated so
cString() is always valid. It inherits from
Object and needs a real heap (-falloc=heap, the
default on the xt 6502 layout and every native backend).
UTF-8 preserves code-point order under byte comparison, so the value methods
(equals, compare, hash) need no
character-aware variants: byte order is character order. Ordering is
lexicographic by unsigned byte then by length, so a prefix sorts before its
extension ("go" before "gone").
Searches return a byte index and a miss is notFound(), never a
negative number. Out-of-range slicing clamps to empty rather than faulting.
Conforms to
Section titled “Conforms to”Comparable:comparegives total ordering, soStringcan be sorted and used as a key.Hashable:hash(FNV-1a over the bytes), soStringcan be aMap/Setkey.Copying:copyreturns an independent duplicate.
Every String* is also an Object* and fits anywhere one is expected.
Topics
Section titled “Topics”Creating strings · withCString · withString · withBytes · withChar · withFormat · withEncodedBytes · init
Numbers → String · withI32 / withU32 · withI16 / withU16 · withI64 / withU64 · withFloat
Reading bytes · byteLength · isEmpty · byteAt · capacity · cString · copyCString · getBytes
Characters (Unicode) · charCount · charAt · charAtByte · charByteLength · byteIndexOfChar · nextCharByte · prevCharByte · isCharBoundary · appendChar · substringChars · isValidUtf8 · sanitizedUtf8
Searching · byteIndexOf · indexOfByte · lastIndexOfByte · contains · hasPrefix · hasSuffix · notFound
Slicing · substringBytes · substringFromByte · substringToByte
Mutating · append · appendCString · appendByte · appendBytes · appendFormat · insertAtByte · insertByte · insertCStringAtByte · deleteByteRange · replaceByteRange · replaceOccurrences · clear · setTo · setCString · reserve
Deriving new strings · appending · replacing · trimmed · uppercased · lowercased · copy · description
Case-insensitive · caseInsensitiveCompare · equalsIgnoringCase
Splitting & joining · splitOnByte · splitOnSet · join
Character sets · byteIndexOfSet · lastByteIndexOfSet · containsByteFromSet · asCharacterSet
Paths · pathSeparator · isAbsolutePath · lastPathComponent · deletingLastPathComponent · pathExtension · deletingPathExtension · appendingPathComponent · appendingPathExtension
Other encodings · withEncodedBytes · (encode via Data.withStringEncoded)
Protocol methods · equals · compare · hash · dealloc
Creating strings
Section titled “Creating strings”withCString
Section titled “withCString”static String* withCString(u8* src)Builds a String by copying a NUL-terminated C string. The bytes are copied unchanged and assumed to be UTF-8, with no validation. This is the most common constructor.
withString
Section titled “withString”static String* withString(String* other)Returns an independent copy of other (same as copy).
withBytes
Section titled “withBytes”static String* withBytes(u8* src, u32 n)Copies n bytes, including any NUL bytes. The buffer may contain embedded NULs,
though cString() stops at the first one.
withChar
Section titled “withChar”static String* withChar(u32 cp)A one-character String: encodes the Unicode code point cp as UTF-8.
withFormat
Section titled “withFormat”static String* withFormat(string fmt, ...)Builds a String from a printf-style format (see appendFormat
for the conversions). String.withFormat("%d items", n).
withEncodedBytes
Section titled “withEncodedBytes”static String* withEncodedBytes(u8* src, u32 n, StrEncoding enc)Decodes n bytes in encoding enc into a (UTF-8) String. Malformed input is
repaired to U+FFFD. See Other encodings.
void init(void)The default initializer (an empty String). Prefer new String() or the
with… constructors; you rarely call init directly.
Numbers → String
Section titled “Numbers → String”withI32 / withU32
Section titled “withI32 / withU32”static String* withI32(i32 v)static String* withU32(u32 v)Decimal rendering of a 32-bit signed / unsigned integer.
withI16 / withU16
Section titled “withI16 / withU16”static String* withI16(i16 v)static String* withU16(u16 v)Convenience wrappers that widen to 32-bit and render as above.
withI64 / withU64
Section titled “withI64 / withU64”static String* withI64(i64 v)static String* withU64(u64 v)Decimal rendering of a 64-bit signed / unsigned integer.
withFloat
Section titled “withFloat”static String* withFloat(float f, u8 precision)static String* withFloat(float f) // precision 6Renders f with precision digits after the point (default 6).
Reading bytes
Section titled “Reading bytes”byteLength
Section titled “byteLength”u32 byteLength(void)Number of bytes in the string (not counting the terminator). O(1). This is the
UTF-8 encoded length, not the character count; see charCount.
isEmpty
Section titled “isEmpty”bool isEmpty(void)true when the byte length is zero.
byteAt
Section titled “byteAt”u8 byteAt(u32 idx)The raw byte at idx. For the character at a position use
charAt or charAtByte.
capacity
Section titled “capacity”u32 capacity(void)Bytes currently allocated in the backing buffer (≥ byteLength).
See reserve.
cString
Section titled “cString”u8* cString(void)A borrowed pointer into the String’s own NUL-terminated buffer. Valid until
the next growth (append, appendChar,
appendFormat, insertAtByte …), which may
reallocate and free the old buffer, leaving the pointer dangling. If the bytes
must outlive the next mutation, use copyCString.
copyCString
Section titled “copyCString”u8* copyCString(void)A new heap copy of the bytes (NUL-terminated) that the caller owns and frees
with delete. Use it when you need a pointer that survives mutation of the
String.
getBytes
Section titled “getBytes”u32 getBytes(u8* dst, u32 max)Copies up to max bytes into dst, returning the number copied. Does not
NUL-terminate. Safe against overrun.
Characters (Unicode)
Section titled “Characters (Unicode)”Available on every target but xt6502.
charCount
Section titled “charCount”u32 charCount(void)Number of Unicode code points, decoded from the UTF-8. O(n).
charAt
Section titled “charAt”u32 charAt(u32 n)The n-th code point. O(n): it restarts from the front on each call, so a
charAt loop is O(n²). Walk by byte index instead (see the example).
charAtByte
Section titled “charAtByte”u32 charAtByte(u32 at)The code point whose encoding starts at byte at. Returns U+FFFD if at is
not a valid sequence start. O(1).
charByteLength
Section titled “charByteLength”u32 charByteLength(u32 at)How many bytes the character starting at byte at occupies (1–4; 1 for an
invalid byte).
byteIndexOfChar
Section titled “byteIndexOfChar”u32 byteIndexOfChar(u32 n)The byte offset where the n-th character’s encoding begins.
nextCharByte
Section titled “nextCharByte”u32 nextCharByte(u32 at)The byte offset of the next character after the one at at. Use it to iterate
characters in O(n).
prevCharByte
Section titled “prevCharByte”u32 prevCharByte(u32 at)The byte offset of the character before the one at at.
isCharBoundary
Section titled “isCharBoundary”bool isCharBoundary(u32 at)true if byte at begins a UTF-8 sequence (or is the end).
appendChar
Section titled “appendChar”void appendChar(u32 cp)Encodes code point cp as UTF-8 and appends it.
substringChars
Section titled “substringChars”String* substringChars(u32 fromChar, u32 count)A new String of count characters starting at character index fromChar.
Clamps to empty if out of range.
isValidUtf8
Section titled “isValidUtf8”bool isValidUtf8(void)true if the whole buffer is well-formed UTF-8 (rejects overlong encodings,
unpaired surrogates, values above U+10FFFF, truncated sequences).
sanitizedUtf8
Section titled “sanitizedUtf8”String* sanitizedUtf8(void)A repaired copy: each maximal invalid subpart becomes one U+FFFD (the
Unicode-recommended repair). Valid input comes back byte-identical.
Searching
Section titled “Searching”Byte offsets; a miss is notFound().
byteIndexOf
Section titled “byteIndexOf”u32 byteIndexOf(String* needle)u32 byteIndexOf(String* needle, u32 from)First byte offset of needle, optionally starting the search at byte from.
indexOfByte
Section titled “indexOfByte”u32 indexOfByte(u8 ch)First offset of byte ch.
lastIndexOfByte
Section titled “lastIndexOfByte”u32 lastIndexOfByte(u8 ch)Last offset of byte ch.
contains
Section titled “contains”bool contains(String* needle)true if needle occurs anywhere (byteIndexOf(needle) != notFound()).
hasPrefix
Section titled “hasPrefix”bool hasPrefix(String* p)true if the string starts with p.
hasSuffix
Section titled “hasSuffix”bool hasSuffix(String* s)true if the string ends with s.
notFound
Section titled “notFound”static u32 notFound(void) // 0xFFFFFFFFThe sentinel returned by the search methods on a miss.
Slicing
Section titled “Slicing”Out-of-range clamps to empty.
substringBytes
Section titled “substringBytes”String* substringBytes(u32 from, u32 len)A new String of len bytes starting at byte from.
substringFromByte
Section titled “substringFromByte”String* substringFromByte(u32 from)Everything from byte from to the end.
substringToByte
Section titled “substringToByte”String* substringToByte(u32 to)Everything before byte to.
Mutating
Section titled “Mutating”These modify the String in place.
append
Section titled “append”void append(String* other)Appends other’s bytes.
appendCString
Section titled “appendCString”void appendCString(u8* src)Appends a NUL-terminated C string.
appendByte
Section titled “appendByte”void appendByte(u8 ch)Appends one raw byte. This may leave the buffer holding partial UTF-8 (see
sanitizedUtf8).
appendBytes
Section titled “appendBytes”void appendBytes(u8* src, u32 n)Appends n bytes.
appendFormat
Section titled “appendFormat”void appendFormat(string fmt, ...)Appends printf-style formatted text. Conversions: %d/%u (16-bit),
%ld/%lu (32-bit), %x/%lx, %s, %c, %f, %%. See
Stdio for the shared format contract.
insertAtByte
Section titled “insertAtByte”void insertAtByte(u32 at, String* other)Inserts other at byte offset at.
insertByte
Section titled “insertByte”void insertByte(u32 at, u8 ch)Inserts one byte at at.
insertCStringAtByte
Section titled “insertCStringAtByte”void insertCStringAtByte(u32 at, u8* src)Inserts a C string at byte at.
deleteByteRange
Section titled “deleteByteRange”void deleteByteRange(u32 at, u32 len)Removes len bytes starting at at.
replaceByteRange
Section titled “replaceByteRange”void replaceByteRange(u32 at, u32 len, String* other)Replaces len bytes at at with other (which may be a different length).
replaceOccurrences
Section titled “replaceOccurrences”u32 replaceOccurrences(String* find, String* sub)Replaces every occurrence of find with sub in place; returns the count
replaced. For a non-mutating version see replacing.
void clear(void)Empties the String (keeps the allocated buffer).
void setTo(String* other)Replaces the contents with a copy of other.
setCString
Section titled “setCString”void setCString(u8* src)Replaces the contents with a C string.
reserve
Section titled “reserve”void reserve(u32 need)Grows the buffer so at least need bytes fit without reallocating, which
amortises a series of appends.
Deriving new strings
Section titled “Deriving new strings”Non-mutating: each returns a new String*, leaving the receiver unchanged.
appending
Section titled “appending”String* appending(String* other)A new String of the receiver followed by other.
replacing
Section titled “replacing”String* replacing(String* find, String* sub)A new String with every find replaced by sub (non-mutating
replaceOccurrences).
trimmed
Section titled “trimmed”String* trimmed(void) // ASCII whitespaceString* trimmed(CharacterSet* set) // any setA copy with leading and trailing whitespace (or the bytes of any
CharacterSet) removed.
uppercased
Section titled “uppercased”String* uppercased(void)An ASCII-uppercased copy (non-ASCII bytes pass through).
lowercased
Section titled “lowercased”String* lowercased(void)An ASCII-lowercased copy.
String* copy(void)An independent duplicate (the Copying method).
description
Section titled “description”String* description(void)A String describing the object; for String itself, a copy. This is the
Object hook used by printing helpers.
Case-insensitive
Section titled “Case-insensitive”These use ASCII case folding only; a full Unicode fold is not provided because of its cost.
caseInsensitiveCompare
Section titled “caseInsensitiveCompare”i8 caseInsensitiveCompare(String* other)Like compare but ASCII-case-insensitive.
equalsIgnoringCase
Section titled “equalsIgnoringCase”bool equalsIgnoringCase(String* other)ASCII-case-insensitive equality.
Splitting & joining
Section titled “Splitting & joining”splitOnByte
Section titled “splitOnByte”Array* splitOnByte(u8 sep)Splits on byte sep, returning an Array of Strings.
Empty fields are kept for consecutive, leading or trailing separators, so
"a,,b" is three fields. Filter out the empty fields if you want tokens.
splitOnSet
Section titled “splitOnSet”Array* splitOnSet(CharacterSet* set)Splits on any byte in set.
static String* join(Array* parts, String* sep)Joins an Array of Strings with sep between them. The inverse of
splitOnByte.
Character sets
Section titled “Character sets”Work with CharacterSet.
byteIndexOfSet
Section titled “byteIndexOfSet”u32 byteIndexOfSet(CharacterSet* set)First byte offset of any character in set.
lastByteIndexOfSet
Section titled “lastByteIndexOfSet”u32 lastByteIndexOfSet(CharacterSet* set)Last byte offset of any character in set.
containsByteFromSet
Section titled “containsByteFromSet”bool containsByteFromSet(CharacterSet* set)true if any byte belongs to set.
asCharacterSet
Section titled “asCharacterSet”CharacterSet* asCharacterSet(void)A CharacterSet of the distinct bytes in this String.
Treat the String as a /-separated path. Non-mutating.
pathSeparator
Section titled “pathSeparator”static u8 pathSeparator(void) // '/'The separator byte these methods use.
isAbsolutePath
Section titled “isAbsolutePath”bool isAbsolutePath(void)true if the path starts at the root (/).
lastPathComponent
Section titled “lastPathComponent”String* lastPathComponent(void)The final component (the file name).
deletingLastPathComponent
Section titled “deletingLastPathComponent”String* deletingLastPathComponent(void)The parent directory (drops the last component).
pathExtension
Section titled “pathExtension”String* pathExtension(void)The extension of the last component, without the dot (empty if none).
deletingPathExtension
Section titled “deletingPathExtension”String* deletingPathExtension(void)The path with the last component’s extension removed.
appendingPathComponent
Section titled “appendingPathComponent”String* appendingPathComponent(String* component)The path with component appended, inserting a separator as needed.
appendingPathExtension
Section titled “appendingPathExtension”String* appendingPathExtension(String* ext)The path with .ext appended to the last component.
Other encodings
Section titled “Other encodings”Internally a String is always UTF-8; there is no per-String encoding mode. Other encodings are transcoded at the edge:
enum StrEncoding = {ENC_UTF8, ENC_ASCII, ENC_LATIN1, ENC_UTF16LE, ENC_UTF16BE};
String* s = String.withEncodedBytes(buf, n, ENC_LATIN1); // decode: bytes -> StringData* d = Data.withStringEncoded(s, ENC_ASCII); // encode: String -> bytes- Decoding (
withEncodedBytes) repairs malformed input toU+FFFD: an unpaired UTF-16 surrogate, an odd trailing byte, an ASCII byte above 127. Latin-1 cannot be malformed, because each byte is its code point. - Encoding (
Data.withStringEncoded) substitutes?for a code point the target cannot express (Latin-1 aboveU+00FF, ASCII aboveU+007F). UTF-16 emits surrogate pairs for the astral planes. ENC_UTF8output is a plain byte copy, including any invalid bytes. CallsanitizedUtf8first if you want repair.
The encoder lives on Data, not String, because Data
already imports String and the bridge is kept on one side.
Protocol methods
Section titled “Protocol methods”Inherited/overridden hooks from Object,
Comparable and Hashable.
equals
Section titled “equals”bool equals(String* other)bool equals(Object* other)Byte-exact equality. The Object* overload lets a String compare inside a
heterogeneous container.
compare
Section titled “compare”i8 compare(String* other)i8 compare(Object* other)Total ordering: lexicographic by unsigned byte, then by length. Returns
negative / zero / positive. This method makes String Comparable.
u32 hash(void)FNV-1a over the bytes. This is the Hashable method,
so a String can key a Map or Set.
dealloc
Section titled “dealloc”void dealloc(void)Frees the backing buffer. ARC calls it when the last reference goes away; you do not call it directly.
Worked example
Section titled “Worked example”Compiles and runs on every target but xt6502 (examples/compiler/strings.xc):
// strings.xc — the String: bytes and characters, named apart.#import "Stdio.xc"#import "Foundation.xc"
i32 main(void){ // "héllo⚡" — 6 characters, 9 bytes: é is 2 bytes, ⚡ is 3. String* s = String.withCString("h"); s.appendChar((u32)$E9); // é U+00E9, encoded as 2 bytes s.appendCString("llo"); s.appendChar((u32)$26A1); // ⚡ U+26A1, encoded as 3 bytes
Stdio.printf("bytes %d, chars %d\n", (i16)s.byteLength(), (i16)s.charCount());
// Byte in the name = byte semantics; Char = code points. Stdio.printf("byteAt(1) %lx, charAt(1) U+%lx\n", (u32)s.byteAt((u32)1), s.charAt((u32)1));
// Walk characters by byte index — no O(n^2) charAt loop. u32 i = (u32)0; while (i < s.byteLength()) { Stdio.printf("U+%lx ", s.charAtByte(i)); i = s.nextCharByte(i); } Stdio.printf("\n"); return 0;}bytes 9, chars 6byteAt(1) 000000C3, charAt(1) U+000000E9U+00000068 U+000000E9 U+0000006C U+0000006C U+0000006F U+000026A1String literals also take Unicode escapes directly: "héllo⚡" is the same
nine bytes. See lexical structure.