substr
Builtin index · Collections & strings
result = substr(s, start, [length])
Input: s, start, length · Output: result
What it is
s is a Str; start (number, 0-based character index, must lie in [0, char_count]) is where the slice begins; optional length (number of characters, default: to the end) is clamped rather than erroring if it runs past what's left. Plain aliases of the same implementation (mid exists purely for BASIC/Excel discoverability).
Overloads
2 forms. Each carries its own inputs, outputs and worked example — pick the tab for the one you are calling.
| Code | Input | Output | Description |
result = substr(s, start) | s Strs is a Str.start numberstart (number, 0-based character index, must lie in [0, char_count]) is where the slice begins. | result Str | Everything from start to the end of s — the 2-argument form. |
Examples
From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.
s = "Hello, World!"
print(substr(s, 7)) # "World!" — to the end
print(substr(s, 0, 5)) # "Hello" — bounded
print(substr(s, 7, 100)) # "World!" — clamped, not an error
print(mid(s, 7, 5)) # "World" — mid is substr under another name
World! Hello World! World
from collections-strings
print("-" * 40) # "----------------------------------------"
print("hello".substr(0, 2).replace("e", "i")) # "hi"
print(pad_left(str(7), 3, "0")) # "007"
print(proper("ada lovelace")) # "Ada Lovelace"
print(count("banana", "a")) # 3
---------------------------------------- hi 007 Ada Lovelace 3
from collections-strings
s = " Hello, Qu World! "
trimmed = trim(s)
parts = split(trimmed, ", ")
print(parts) # ["Hello", "Qu World!"]
print(upper(parts[0])) # HELLO
print(starts_with(trimmed, "Hello")) # true
print("hello".substr(0, 2).replace("e", "i").flip().flip())
print("hi world".split(" ").join(", ") + "!")
("Hello", "Qu World!")
HELLO
true
hi
hi, world!from collections-strings
| Code | Input | Output | Description |
result = substr(s, start, length) | s Strs is a Str.start numberstart (number, 0-based character index, must lie in [0, char_count]) is where the slice begins.length numberoptional length (number of characters, default: to the end) is clamped rather than erroring if it runs past what's left. | result Str | Exactly length characters starting at start, clamped (not an error) if length runs past what's left — the 3-argument form. |
Examples
From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.
s = "Hello, World!"
print(substr(s, 7)) # "World!" — to the end
print(substr(s, 0, 5)) # "Hello" — bounded
print(substr(s, 7, 100)) # "World!" — clamped, not an error
print(mid(s, 7, 5)) # "World" — mid is substr under another name
World! Hello World! World
from collections-strings
How it works
All index/length arguments below are 0-based (matching every other index in this codebase) and unicode-aware: built on .chars(), never a raw byte slice, so a multi-byte UTF-8 string indexes by character, not by byte (a naive byte slice would panic or corrupt on non-ASCII input). substr(s, start[, length]) / mid(s, start, length) — plain aliases of the same implementation: MATLAB has no mid at all (that's a BASIC/Excel convention), and since Qu already indexes 0-based everywhere (unlike BASIC/Excel's 1-based MID$), there is no real semantic difference to preserve — mid exists purely for discoverability by BASIC/Excel habit. start must be within [0, char_count] (== char_count is the valid "nothing left" case, matching the empty-slice-at-the-end convention s[n:] uses elsewhere); length is clamped to whatever is actually available rather than erroring — asking for more than what's left (substr(s, 0, 1000) to mean "the rest") is a common, harmless overshoot, unlike a genuinely out-of-range start.
From the note above this builtin in the interpreter, where the reasoning was written down as it was built.
See also
mid — documented in the same entry.