str
Everything to do with text: searching, slicing, replacing, digits, case, and building long strings.
import str
The str package is the one you will reach for most. Anywhere you touch text, from reading user input to building output, its functions apply.
One thing to know before you start: Salam strings are UTF-8. In UTF-8 an English letter is one byte, while a letter in most other scripts takes two or more. That is why most of these functions come in two forms: Len, Substr and IndexOf work in bytes and are fast, while CharCount, CharSubstr and CharFind work in characters. Wherever the count or the cut has to match what the reader sees, use the character form.
One step further out is the "grapheme": what a reader sees as a single letter. A letter with an accent is two characters but one grapheme, and a family emoji is seven characters but one grapheme. For reversing or cutting text that carries marks or emoji, the grapheme functions are the safe ones.
Three methods also sit on every string and need no import: text.starts_with("salam"), text.ends_with(".txt") and text.includes("world"). All three return true or false and behave the same on every backend.
Types
StringBuilder
struct StringBuilderNewBuilder and use it through the Buf functions; do not change its fields directly.| Name | Type | Description |
|---|---|---|
data | void* | The address of the memory the text is written into. |
len | i64 = 0 | How many bytes have been written so far. |
cap | i64 = 0 | The size of the memory taken, in bytes. It grows by itself when it fills up. |
import str
func main:
mut b := str.NewBuilder()
defer str.BufFree(b)
println str.BufIsEmpty(b)
repeat 1 to 3 in i:
str.BufAppend(b, "part ")
str.BufAppendInt(b, i)
str.BufAppendChar(b, 44)
end
str.BufAppendCp(b, 1776)
println str.BufStr(b)
println str.BufLen(b), str.BufIsEmpty(b)
str.BufReset(b)
println str.BufLen(b)
endFunctions
Contains
func Contains(s: str, sub: str): boolsub occurs anywhere in the string.import str
func main:
s := "salam, salam world"
println str.Contains(s, "world"), str.StartsWith(s, "salam"), str.EndsWith(s, "world")
println str.IndexOf(s, "salam"), str.LastIndex(s, "salam"), str.Search(s, "missing")
println str.IndexFrom(s, "salam", 1), str.Count(s, "salam")
endStartsWith
func StartsWith(s: str, prefix: str): boolprefix.The example for this item is shown with the ones above: str-Contains.salam
EndsWith
func EndsWith(s: str, suffix: str): boolsuffix.The example for this item is shown with the ones above: str-Contains.salam
Search
func Search(s: str, sub: str): intsub in bytes, or minus one. It is the same as IndexOf.The example for this item is shown with the ones above: str-Contains.salam
IndexOf
func IndexOf(s: str, sub: str): intsub in bytes, or minus one when it is not found.The example for this item is shown with the ones above: str-Contains.salam
IndexFrom
func IndexFrom(s: str, sub: str, from: int): intIndexOf, but starts the search at byte from, for finding the next occurrence.The example for this item is shown with the ones above: str-Contains.salam
Count
func Count(s: str, sub: str): intsub in the string.The example for this item is shown with the ones above: str-Contains.salam
LastIndex
func LastIndex(s: str, sub: str): intsub in bytes, or minus one.The example for this item is shown with the ones above: str-Contains.salam
DigitValue
func DigitValue(cp: int): intimport str
func main:
println str.ToPersianDigits("order 1403")
println str.ToEnglishDigits("code ۱۲۳ and ٤٥٦")
println str.ToArabicDigits("2025")
println str.HasPersianDigits("۱۲"), str.HasArabicDigits("۱۲"), str.HasEnglishDigits("12")
d := str.CodePoints("۷").get(0)
println str.IsPersianDigit(d), str.IsArabicDigit(d), str.IsAnyDigit(d)
println str.DigitValue(d), str.DigitValue(65)
endIsArabicDigit
func IsArabicDigit(cp: int): bool٠ to ٩. Persian digits have a different shape and do not count here.The example for this item is shown with the ones above: str-Digits.salam
IsPersianDigit
func IsPersianDigit(cp: int): bool۰ to ۹.The example for this item is shown with the ones above: str-Digits.salam
IsAnyDigit
func IsAnyDigit(cp: int): boolThe example for this item is shown with the ones above: str-Digits.salam
ToEnglishDigits
func ToEnglishDigits(s: str): strThe example for this item is shown with the ones above: str-Digits.salam
ToArabicDigits
func ToArabicDigits(s: str): strThe example for this item is shown with the ones above: str-Digits.salam
ToPersianDigits
func ToPersianDigits(s: str): strThe example for this item is shown with the ones above: str-Digits.salam
HasEnglishDigits
func HasEnglishDigits(s: str): boolThe example for this item is shown with the ones above: str-Digits.salam
HasArabicDigits
func HasArabicDigits(s: str): boolThe example for this item is shown with the ones above: str-Digits.salam
HasPersianDigits
func HasPersianDigits(s: str): boolThe example for this item is shown with the ones above: str-Digits.salam
GraphemeCount
func GraphemeCount(s: str): intimport str
func main:
s := "کَتاب👨👩👧"
println str.CharCount(s), str.GraphemeCount(s)
println str.Graphemes(s)
println str.ReverseGraphemes("سَلام")
endGraphemes
func Graphemes(s: str): Vector<str>The example for this item is shown with the ones above: str-Graphemes.salam
ReverseGraphemes
func ReverseGraphemes(s: str): strThe example for this item is shown with the ones above: str-Graphemes.salam
NFD
func NFD(s: str): strimport str
func main:
composed := "آ"
decomposed := str.NFD(composed)
println composed.len(), decomposed.len(), composed == decomposed
println str.NFC(decomposed) == composed
println str.IsNFC(composed), str.IsNFC(decomposed)
presentation := "ﻼ"
println str.NFKD(presentation), str.NFKC(presentation)
endNFC
func NFC(s: str): strThe example for this item is shown with the ones above: str-NFC.salam
NFKD
func NFKD(s: str): strﻻ, for instance, become ordinary letters.The example for this item is shown with the ones above: str-NFC.salam
NFKC
func NFKC(s: str): strThe example for this item is shown with the ones above: str-NFC.salam
IsNFC
func IsNFC(s: str): boolThe example for this item is shown with the ones above: str-NFC.salam
Upper
func Upper(s: str): strimport str
func main:
println str.Upper("salam"), str.Lower("SALAM"), str.Title("hello world")
println str.EqualFold("Straße", "STRASSE")
println str.CompareFold("abc", "ABX")
println str.Upper("سلام")
endLower
func Lower(s: str): strThe example for this item is shown with the ones above: str-Upper.salam
Title
func Title(s: str): strThe example for this item is shown with the ones above: str-Upper.salam
EqualFold
func EqualFold(a: str, b: str): boolThe example for this item is shown with the ones above: str-Upper.salam
CompareFold
func CompareFold(a: str, b: str): intThe example for this item is shown with the ones above: str-Upper.salam
CodePointAt
func CodePointAt(s: str, i: int, cp &: int): inti, puts its code point in cp and returns how many bytes it took. For walking a string by hand, character by character.import str
func main:
s := "سلام"
println str.Len(s), str.CharCount(s)
println str.CharAtIndex(s, 1), str.CharSubstr(s, 1, 2)
println str.CharFind(s, "ام"), str.Reverse(s)
println str.CharAt(s, 2)
mut code := 0
width := str.CodePointAt(s, 0, code)
println code, width, str.CharLen(216)
points := str.CodePoints(s)
println points
println str.FromCodePoints(points)
println str.Chars("ab۱")
println str.AllAscii("salam"), str.AllAscii("سلام")
endCharLen
func CharLen(lead: int): intThe example for this item is shown with the ones above: str-CharCount.salam
CharAt
func CharAt(s: str, i: int): stri. That is a byte position, not a character position; for a character position see CharAtIndex.The example for this item is shown with the ones above: str-CharCount.salam
Reverse
func Reverse(s: str): strReverseGraphemes is the correct one.The example for this item is shown with the ones above: str-CharCount.salam
CharCount
func CharCount(s: str): int"سلام" it is four, while Len says eight.The example for this item is shown with the ones above: str-CharCount.salam
CharSubstr
func CharSubstr(s: str, start: int, n: int): strn characters starting at character start. It is the safe version of Substr for text outside ASCII.The example for this item is shown with the ones above: str-CharCount.salam
CharAtIndex
func CharAtIndex(s: str, i: int): stri, counting from zero.The example for this item is shown with the ones above: str-CharCount.salam
CharFind
func CharFind(s: str, sub: str): intsub in characters, or minus one when it is not there.The example for this item is shown with the ones above: str-CharCount.salam
CodePoints
func CodePoints(s: str): Vector<int>The example for this item is shown with the ones above: str-CharCount.salam
FromCodePoints
func FromCodePoints(cps: Vector<int>): strCodePoints: builds a string from a vector of code points.The example for this item is shown with the ones above: str-CharCount.salam
AllAscii
func AllAscii(s: str): boolThe example for this item is shown with the ones above: str-CharCount.salam
Chars
func Chars(s: str): Vector<str>The example for this item is shown with the ones above: str-CharCount.salam
Repeat
func Repeat(s: str, n: int): strn times, one after another; good for drawing a separator line.import str
func main:
println str.Repeat("=-", 5)
words := str.Fields(" the Salam programming\tlanguage \n")
println words.len(), words
endFields
func Fields(s: str): Vector<str>The example for this item is shown with the ones above: str-Fields.salam
NewBuilder
func NewBuilder(): StringBuilder+ over and over. Release it with BufFree when you are done.The example for this item is shown with the ones above: str-StringBuilder.salam
BufAppend
func BufAppend(b &: StringBuilder, s: str)The example for this item is shown with the ones above: str-StringBuilder.salam
BufAppendChar
func BufAppendChar(b &: StringBuilder, code: int)The example for this item is shown with the ones above: str-StringBuilder.salam
BufAppendCp
func BufAppendCp(b &: StringBuilder, cp: int)The example for this item is shown with the ones above: str-StringBuilder.salam
BufAppendInt
func BufAppendInt(b &: StringBuilder, n: i64)The example for this item is shown with the ones above: str-StringBuilder.salam
BufLen
func BufLen(b &: StringBuilder): i64The example for this item is shown with the ones above: str-StringBuilder.salam
BufIsEmpty
func BufIsEmpty(b &: StringBuilder): boolThe example for this item is shown with the ones above: str-StringBuilder.salam
BufStr
func BufStr(b &: StringBuilder): strThe example for this item is shown with the ones above: str-StringBuilder.salam
BufReset
func BufReset(b &: StringBuilder)The example for this item is shown with the ones above: str-StringBuilder.salam
BufFree
func BufFree(b &: StringBuilder)defer right after creating the builder.The example for this item is shown with the ones above: str-StringBuilder.salam
Len
func Len(s: str): intCharCount.import str
func main:
a := "apple"
b := "pear"
println str.Len(a), str.IsEmpty(""), str.IsEmpty(a)
println str.Concat(a, b)
println str.Compare(a, b), str.Compare(b, a), str.Compare(a, "apple")
println str.Equals(a, "apple")
println str.Substr("salam donya", 6, 5), str.SubstrIn("salam", 3, 10)
println str.Find("salam donya", "donya")
c := str.Clone(a)
println c
endByteLen
func ByteLen(s: str): intLen counts UTF-16 units, so use this one for byte-level work.import str
func main:
s := "سلام"
println str.ByteLen(s), str.CharCount(s)
println str.ByteSub(s, 0, 4)
println str.CharSubstr(s, 0, 2)
endByteSub
func ByteSub(s: str, start: int, n: int): strn bytes starting at byte start. The C and LLVM backends return the bytes untouched, but the JavaScript backend decodes them as UTF-8, so a cut that falls inside a multi-byte character produces a replacement character and a different byte length. For cutting by character use CharSubstr.The example for this item is shown with the ones above: str-ByteLen.salam
Concat
func Concat(a: str, b: str): str+ does.The example for this item is shown with the ones above: str-Len.salam
Compare
func Compare(a: str, b: str): intThe example for this item is shown with the ones above: str-Len.salam
Equals
func Equals(a: str, b: str): bool== does.The example for this item is shown with the ones above: str-Len.salam
Substr
func Substr(s: str, start: int, n: int): strn bytes starting at byte start. Outside ASCII, take care not to cut through the middle of a character, or use CharSubstr instead.The example for this item is shown with the ones above: str-Len.salam
SubstrIn
func SubstrIn(s: str, start: int, n: int): strSubstr, but when the range runs past the end of the string it does not fail and returns only the part that is there.The example for this item is shown with the ones above: str-Len.salam
Find
func Find(s: str, sub: str): intsub in bytes, or minus one.The example for this item is shown with the ones above: str-Len.salam
Split
func Split(s: str, delim: str): Vector<str>delim occurs and returns the pieces in a vector. Free the vector when you are done with it.import str
func main:
parts := str.Split("apple,pear,grape", ",")
defer parts.free()
println parts.len(), parts.get(1)
println str.Join(parts, " / ")
endJoin
func Join(parts: Vector<str>, sep: str): strsep between them; the reverse of Split.The example for this item is shown with the ones above: str-Split.salam
Trim
func Trim(s: str): strimport str
func main:
s := " hello world "
println "[" + str.Trim(s) + "]"
println "[" + str.TrimLeft(s) + "]"
println "[" + str.TrimRight(s) + "]"
println str.TrimPrefix("https://salamlang.ir", "https://")
println str.TrimSuffix("report.txt", ".txt")
endToInt
func ToInt(s: str): intimport str
func main:
println str.ToInt("42") + 1, str.ToInt("abc")
println str.ToFloat("2.5") * 2
println "[" + str.FromInt(-15) + "]", "[" + str.FromFloat(1.25) + "]"
endToFloat
func ToFloat(s: str): f64The example for this item is shown with the ones above: str-ToInt.salam
IsEmpty
func IsEmpty(s: str): boolThe example for this item is shown with the ones above: str-Len.salam
Clone
func Clone(s: str): strThe example for this item is shown with the ones above: str-Len.salam
Replace
func Replace(s: str, find: str, replacement: str): strfind with replacement.import str
func main:
println str.Replace("I like apples, red apples", "apple", "pear")
endFromInt
func FromInt(i: i64): strThe example for this item is shown with the ones above: str-ToInt.salam
FromFloat
func FromFloat(f: f64): strThe example for this item is shown with the ones above: str-ToInt.salam
IsAscii
func IsAscii(code: int): boolimport str
func main:
each s in ["A", "z", "7", " ", "!", "ب", "۷", "\t"]:
c := str.CodePoints(s).get(0)
println "[" + s + "]", str.IsAscii(c), str.IsAlpha(c), str.IsDigit(c), str.IsSpace(c), str.IsPunct(c)
end
println str.IsAsciiUpper(65), str.IsAsciiLower(65), str.IsUpper(1040), str.IsLower(1072)
println str.IsAsciiDigit(50), str.IsAsciiAlpha(50), str.IsAsciiAlnum(50), str.IsAsciiSpace(32)
println str.IsAlnum(1776), str.IsMark(1614), str.IsControl(10)
endIsAsciiSpace
func IsAsciiSpace(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsAsciiDigit
func IsAsciiDigit(code: int): bool0 to 9.The example for this item is shown with the ones above: str-IsAscii.salam
IsAsciiUpper
func IsAsciiUpper(code: int): boolA to Z.The example for this item is shown with the ones above: str-IsAscii.salam
IsAsciiLower
func IsAsciiLower(code: int): boola to z.The example for this item is shown with the ones above: str-IsAscii.salam
IsAsciiAlpha
func IsAsciiAlpha(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsAsciiAlnum
func IsAsciiAlnum(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsSpace
func IsSpace(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsDigit
func IsDigit(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsUpper
func IsUpper(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsLower
func IsLower(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsAlpha
func IsAlpha(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsAlnum
func IsAlnum(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsPunct
func IsPunct(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsMark
func IsMark(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
IsControl
func IsControl(code: int): boolThe example for this item is shown with the ones above: str-IsAscii.salam
TrimLeft
func TrimLeft(s: str): strThe example for this item is shown with the ones above: str-Trim.salam
TrimRight
func TrimRight(s: str): strThe example for this item is shown with the ones above: str-Trim.salam
TrimPrefix
func TrimPrefix(s: str, prefix: str): strprefix, removes it; otherwise returns the string untouched.The example for this item is shown with the ones above: str-Trim.salam
TrimSuffix
func TrimSuffix(s: str, suffix: str): strsuffix, removes it; handy for stripping a file extension.The example for this item is shown with the ones above: str-Trim.salam