Strings and slicing#
Both single and double quotes create strings. Boolean literals are true and
false (lowercase). Strings are immutable values: these methods return results
without changing the original binding.
Triple double quotes make a string that spans lines, keeping its line breaks,
indentation, and any " inside it; escapes such as \t still work:
banner = """Marslang
says "hello"
to\tyou""";
The text is taken exactly as written, so the line break after an opening """
and the indentation of the lines are part of the string. Docstrings are the
exception: @Decorator.docstring removes the indentation they share.
Raw strings#
An r straight before the opening quote makes a raw string, in which a
backslash is only a backslash and escapes nothing. Use them for
regular expressions and Windows paths:
pattern = r"\d{4}-\d{2}"; // the same as "\\d{4}-\\d{2}"
folder = r"C:\Users\ada\new"; // \n is not a line break here
All three quotes work: r"...", r'...', and r"""...""", which spans
lines. A raw string cannot contain its own closing quote, so a " goes in
r'...' or r"""...""". In an ordinary string, a backslash before a
character without an escape of its own stands for that character, so "\d"
is just d, which is why patterns need raw strings.
f-strings#
An f before the opening quote puts values into the text: each {expression}
is replaced by its value, written as string(value) writes it.
func m{
name = "Ada";
age = 36;
out(f"{name} is {age}, and {age + 1} next year"); // Ada is 36, and 37 next year
out(f"{name.upper()} has {name.len()} letters"); // ADA has 3 letters
out(f"{{braces}} are written twice"); // {braces} are written twice
}
Any expression works between the braces: arithmetic, calls, methods, members,
and indexes. The expressions run from left to right, once each. {{ and }}
are braces themselves, and escapes such as \t work in the text as in any
string. All three quotes work: f"...", f'...', and f"""...""", which spans
lines.
A string inside the braces needs the other kind of quote, since the first "
would end the f-string: f"{scores.get('ada')}", or \" as in
f"{name.replace(\"-\", \" \")}". In f"""...""", plain " works.
There is no format after a : as in other languages; format a number with
std.format inside the braces:
f"Total: {format.fixed(price, 2)}". An f-string cannot also be raw.
Characters#
A character is one Unicode extended grapheme cluster: a visible character can
contain multiple Unicode code points. Chinese 中, Japanese あ, Arabic عَ,
é, 🇨🇳, 👍🏽, and 👨👩👧👦 each count as one.
Length, iteration, reversal, and slicing all use this unit. They do not normalize
the text. Segmentation uses the Rust unicode-segmentation crate (Unicode
extended grapheme cluster rules); its Unicode version follows the crate version.
Methods#
| Call | Result |
|---|---|
text[i] / text.iget(i) |
The character at position i, counting from 0 |
text.len() |
Number of characters |
text.reverse() |
New string with characters in reverse order |
text.slice(start,end) |
New string selecting positions [start,end) |
text.lenslice(start,length) |
New string selecting length characters from start |
text.split() / text.split(sep) |
Array of the words between runs of whitespace / of the parts between each sep; an empty sep raises RangeError |
text.lines() |
Array of lines, splitting at \n or \r\n |
text.strip() / lstrip() / rstrip() |
Without whitespace at both ends / the start / the end |
text.strip(chars) / lstrip(chars) / rstrip(chars) |
Without any of the characters in chars at those ends |
text.upper() / text.lower() |
Unicode case conversion ("Straße".upper() is "STRASSE") |
text.replace(old,new) |
Every occurrence of old replaced; an empty old raises RangeError |
text.find(part) / text.rfind(part) |
Position of the first / last occurrence, or -1 |
text.contains(part) / starts_with(part) / ends_with(part) |
Boolean |
text.copy() |
The same immutable string value |
Every method returns a new value; the string itself never changes, so
text[0] = "x" is a compile error. Positions, searches, and splits work in
whole characters: "café".find("e") is -1 when the é is e plus a combining
accent, because that accent belongs to the same character. An index outside the
string raises OutOfBoundsError, and one that is not a whole number TypeError.
The std.strings functions do the same as these methods, for
code that prefers strings.split(text, ",").
Counting from the end#
Both slicing methods accept an optional third boolean argument. It defaults to
false. Write reverse=true or pass true positionally. A boolean expression is
also accepted. Named reverse= must follow exactly two positional arguments and
must be last. No other named arguments are supported.
With reverse=true, position zero is the last character. Selection proceeds
toward the beginning, but the result keeps the original text order.
| Expression | Result |
|---|---|
"ABCDE".lenslice(0,3) |
"ABC" |
"ABCDE".lenslice(0,3,reverse=true) |
"CDE" |
"ABCDE".lenslice(1,3,reverse=true) |
"BCD" |
"ABCDE".slice(1,4,reverse=true) |
"BCD" |
"ABCDE".lenslice(0,3,reverse=true).reverse() |
"EDC" |
For slice, the end remains exclusive in the chosen direction. For a string of
length N, reverse slice(start,end) selects the forward interval
[N-end,N-start). Reverse lenslice(start,length) selects
[N-start-length,N-start).
Bounds and errors#
- Positions and lengths must be integers. Fractional values, strings, and booleans
raise
TypeError;longintvalues are accepted when within range. - Negative positions/lengths, starts beyond the string length, reversed intervals
(
end < start), and ranges exceeding available characters raiseOutOfBoundsError. - A zero-length slice returns
"". Its start may equal the string length, in either direction. The empty string acceptslenslice(0,0)andslice(0,0). - Two or three arguments are required. The optional reverse value must be a boolean;
invalid arity or flag type raises
TypeError.
Slices never silently truncate. For example, "ABC".lenslice(0,4) raises
OutOfBoundsError, and "ABC".lenslice(3,0,reverse=true) returns "".
Iteration#
func m{
for (ch, "中é👨👩👧👦"){
out(ch);
out(ch.len()); // Each prints 1.
}
}
Only the string APIs listed here are supported language contracts. Calling any
other method on a string raises TypeError.