std/text
Char, a Unicode scalar value, and String, always-valid UTF-8 text with no length() and no indexing by character.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
Die generierte Referenz von std/text zeigt jede öffentliche Deklaration mit Signatur, Doc-Kommentar und Beispielen.
std/text is UTF-8 text and the Unicode scalar value it is made of. Bool used to live here and is std/core's: it is
a primitive of the language, not a thing about text. Every name below is already in scope through the prelude.
Import#
use Char, String from "std/text"const shout = "hello".toUpperCase()
print shoutDeclarations#
Char#
native type Char with Equals, Compare, Hash, Show {
native fn isDigit(): Bool
native fn isLetter(): Bool
native fn isWhitespace(): Bool
native fn byteLength(): Int
native fn toUpperCase(): Self
native fn toLowerCase(): Self
native fn showNested(): String
}
extend Char with TryFrom<Int64, NumberRangeError>A Unicode scalar value. byteLength() is the number of bytes the character takes up in UTF-8 (1 to 4), which is what it
adds to an offset into a String. Inside another value it shows in single quotes with escapes ('A'); Int.from('A')
is the code point and belongs to std/number, which owns Int64, and Char.tryFrom(value) is the other direction and
belongs here, because not every Int64 is a Unicode scalar value (surrogates, and everything above 0x10FFFF).
Letters, whitespace and case come from the Unicode Character Database, pinned at one version (17.0.0) and read from
tables generated into the runtime (tools/unicode/generate.trb, runtime/README.md). isLetter() is the general
category Lu, Ll, Lt, Lm or Lo, isWhitespace() is the White_Space property, and toUpperCase() and toLowerCase() of a
Char are the simple one-to-one mapping, so 'ß'.toUpperCase() is 'ß': its upper case is the two code points SS,
which a Char cannot hold.
TextIndex#
type TextIndex with Equals, Compare, Hash, Show {
fn compare(other: Self): Ordering
fn show(): String
}A position in one text: before one of its characters, or at its end. Only a text hands one out - indexOf,
lastIndexOf, start(), end(), indexAfter, indexBefore, indexedChars() - so a position inside of a
character cannot be written, and text[3..] is a compile error (docs/design/PANICS.md section 4). It holds a byte
offset and shows as one; it has no arithmetic, because at + 1 is exactly the mistake it exists to prevent. A number
from outside becomes one through indexAt(byteOffset:), which answers None inside of a character, and one becomes a
number again through byteOffset(of:).
String#
native type String with Equals, Compare, Hash, Show, Add, Slice<TextIndex>, From<Iterate<Char>> {
static fn from(value: Iterate<Char>): Self
fn chars(): Iterate<Char>
fn bytes(): Bytes
fn charAt(at: TextIndex): Char?
native fn charAtByte(offset: Int): Char?
fn start(): TextIndex
fn end(): TextIndex
fn indexAfter(at: TextIndex): TextIndex?
fn indexBefore(at: TextIndex): TextIndex?
fn indexAt(byteOffset: Int): TextIndex?
fn byteOffset(of: TextIndex): Int
fn indexedChars(): Iterate<(index: TextIndex, character: Char)>
native fn byteAt(offset: Int): UInt8?
native fn byteLength(): Int
native fn isEmpty(): Bool
native fn showNested(): Self
fn slice(range: Bounds<TextIndex>): Self
fn part(range: Bounds<TextIndex>): Self?
native fn sliceBytes(from: Int, to: Int): Self
native fn contains(part: Self): Bool
native fn startsWith(prefix: Self): Bool
native fn endsWith(suffix: Self): Bool
fn indexOf(part: Self): TextIndex?
fn lastIndexOf(part: Self): TextIndex?
native fn byteOffsetOf(part: Self): Int?
native fn lastByteOffsetOf(part: Self): Int?
fn substringBefore(part: Self): Self?
fn substringAfter(part: Self): Self?
fn withoutPrefix(part: Self): Self?
fn withoutSuffix(part: Self): Self?
fn splitOnce(separator: Self): (before: Self, after: Self)?
fn dropping(characters: Int): Self
fn droppingLast(characters: Int): Self
fn prefix(characters: Int): Self
fn suffix(characters: Int): Self
native fn trim(): Self
native fn toUpperCase(): Self
native fn toLowerCase(): Self
native fn replace(part: Self, replacement: Self): Self
native fn split(separator: Self): List<Self>
native fn repeat(times: Int): Self
fn isBlank(): Bool
fn lines(): List<Self>
}UTF-8 text. There is no length() and no text[i] on purpose: say what is being counted (chars(), bytes()). A
position comes from the text and is a TextIndex, and slicing at one is O(1) and shares the storage with the original. A String is always valid UTF-8 - the only ways to build one are a literal, a slice at a character
boundary, String.from(Iterate<Char>) and a runtime function that validates, so reading bytes that are not UTF-8 is an
IoError and there is no replacement character anywhere in the language. showNested() is the text itself in double
quotes with escapes; show() (from Show) is the text unquoted. String.from(characters) and
characters.to<String>() come from extend String with From<Iterate<Char>>.
charAt(at) decodes the character that begins at a position, or answers None at the end. slice(range) is
text[from..to] between two positions and is ordinary TorbScript over sliceBytes(from, to), the one native the runtime
has for it; only a position of another text - past the end of this one or inside one of its characters - and a start
after the end panic, with the offset and the length named. part(range) is its total twin: the same text where slice
would answer one, and None where it would panic.
The byte-level members are for a format that counts bytes - a lexer's spans, a protocol's offsets: byteLength(),
byteAt(offset) (a byte is never inside anything, so it never panics), sliceBytes(from, to), byteOffsetOf(part),
lastByteOffsetOf(part) and charAtByte(offset). Their offsets are Ints the program computed, so an offset inside
of a character panics there, with the offset and the length in the message: the name says what is counted.
toUpperCase() and toLowerCase() of a String are the full default case conversion (Unicode core specification,
section 3.13), so the result can be longer than the text: "ß".toUpperCase() is "SS", "ʼn" becomes "ʼN" and "ffi"
becomes "FFI". A capital sigma lower-cases to ς at the end of a word and to σ anywhere else (Final_Sigma). The
conversion has no locale, so there is no Turkish dotless i and no Lithuanian dot; "İ".toLowerCase() is an i and a
combining dot above, as the standard says by default.
bytes() answers Bytes, the prelude's Buffer<UInt8>, like every other bytes() of the standard library: a
copy of the UTF-8 in one allocation, which is what a sink, a socket, a file and a digest take. It is not a view like
chars(), because nearly every caller wants the list, and the storage itself cannot be shared, because a text's and a
list's are laid out differently. A loop that only reads and must not allocate walks byteAt(offset) up to
byteLength() instead.
const bytes = "hé".bytes()
print bytes // prints [104, 195, 169]The total vocabulary cuts a text without an offset, and none of it can panic. withoutPrefix(part) and
withoutSuffix(part) answer the rest, or None where the text does not start or end with part. splitOnce(separator)
answers (before:, after:) around the first occurrence, or None - one search, Go's strings.Cut.
dropping(characters: n), droppingLast(characters: n), prefix(characters: n) and suffix(characters: n) count
Unicode scalar values and are total like skip and take of an Iterate: fewer characters than asked answers the
empty or the whole text, and a count of zero or less drops or takes nothing. They walk the count, not the text.
const file = "main.trb"
print(file.withoutSuffix(".trb") ?? file) // prints main
print "Grüße".dropping(characters: 2) // prints üße
print("key=value".splitOnce("=")?.after ?? "") // prints valueRelated#
- Strings - why a
Stringhas nolength()and notext[i]. - std/core -
Equals,Compare,HashandShow, which every type here carries. - The standard library - the other packages.