strings
Package strings.
Search, trim, case, split and join on str. The package cannot be named str because that token is the type — the same reason Go calls its own strings.
import "strings";
strings.find("hello world", "world"); // 6, or -1
strings.rfind("a/b/c", "/"); // 3
strings.contains("hello", "ell");
strings.has_prefix("hello", "he");
strings.has_suffix("hello", "lo");
strings.count("a,b,c", ","); // 2
strings.trim(" hi \r\n"); // "hi" (space/tab/CR/LF)
strings.trim_start(s); strings.trim_end(s);
strings.to_upper("hi"); strings.to_lower("HI"); // ASCII only
strings.slice("hello", 1, 3); // "el"
strings.slice("hello", -3, 5); // "llo" — negative counts back
strings.repeat("ab", 3); // "ababab"
strings.replace("a,b,c", ",", " | ");
strings.split("a,b,,c", ","); // ["a", "b", "", "c"]
strings.join(parts, ","); // the inverse of split
strings.join_bytes(parts, b","); // the same for [bytes]: sized once, copied once
strings.from_float(0.1 + 0.2); // "0.30000000000000004"
strings.escape_html("<a href='x'>"); // "<a href='x'>"
strings.escape_js("it's </script>"); // "it\u0027s \u003c/script\u003e"escape_html writes & < > " ' as character references, which is safe in text and in a quoted attribute of either quote. escape_js makes the inside of a JavaScript string literal of any quote (', " or a backquote), safe inside <script> and inside an attribute. Both return the input itself, with no allocation, when nothing needs escaping. template escapes every value through them.
from_float returns the shortest text that to_float reads back as exactly the same number, as to_str, println, inspect and json.encode now do too (they used six significant digits, so to_str(123456789.125) was "1.23457e+08"). The difference is the names: from_float writes NaN and the infinities as NaN, Infinity and -Infinity, where to_str writes nan, inf and -inf.
This is a compiler-provided native package, and it has to be: str supports len, + and == and nothing else — it cannot be indexed or sliced — so none of it could be written in slang without converting to bytes and back on every call. byteutil covers the bytes side.
Three behaviours worth knowing:
- Indices are byte offsets and the case operations are ASCII-only.
stris UTF-8 bytes, and these are byte operations, which is what protocol text (header names, methods, config keys) wants. For text people type, useunicode: characters, case folding and normalisation. sliceclamps rather than panics. Slicing is how you narrow a string you just searched, and afindthat returned -1 on the line above should not turn the next line into a crash. A negative index counts from the end.splitandjoinare exact inverses. Adjacent separators produce empty elements, so the result always hascount(s, sep) + 1elements andjoin(split(s, sep), sep) == sfor any non-empty separator. An empty separator splits into single bytes.
API#
strings.find(str, str) -> int#strings.rfind(str, str) -> int#strings.contains(str, str) -> bool#strings.has_prefix(str, str) -> bool#strings.has_suffix(str, str) -> bool#strings.count(str, str) -> int#strings.trim(str) -> str#strings.trim_start(str) -> str#strings.trim_end(str) -> str#strings.to_upper(str) -> str#strings.to_lower(str) -> str#strings.slice(str, int, int) -> str#strings.repeat(str, int) -> str#strings.replace(str, str, str) -> str#strings.split(str, str) -> [str]#strings.join([str], str) -> str#strings.join_bytes([bytes], bytes) -> bytes#strings.bytes_zero(int) -> bytes#strings.from_bytes(bytes, int, int) -> str#strings.from_bytes_lower(bytes, int, int) -> str#strings.from_wire(wire, int, int) -> str#strings.from_wire_lower(wire, int, int) -> str#strings.find_field(bytes, str) -> int#strings.from_float(float) -> str#strings.escape_html(str) -> str#strings.escape_js(str) -> str#