You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// Map: shift each character
val shifted = S("abc").Map((r rune) => r + 1)
// shifted.ToString() == "bcd"
// Filter: keep only vowels
val vowels = S("hello world").Filter((r rune) => {
return r == rune(97) || r == rune(101) || r == rune(105) || r == rune(111) || r == rune(117)
})
// vowels.ToString() == "eoo"
// Fold: count characters
val count = S("hello").Fold(0, (acc int, r rune) => acc + 1)
// count == 5
Predicate Methods
// These delegate to ForAll for efficiency
S("hello").IsAlpha() // true
S("12345").IsNumeric() // true
S("hello123").IsAlphanumeric() // true
S(" \t").IsWhitespace() // true
S("HELLO").IsUpper() // true
S("hello").IsLower() // true
Pattern Matching
func describe(s Str) string = s match {
case EmptyStr(_) => "empty"
case NonEmptyStr(head, tail) => {
if tail.IsEmpty() {
return "single character: " + string(head)
}
return "starts with " + string(head) + ", rest: " + tail.ToString()
}
}
describe(S("")) // "empty"
describe(S("a")) // "single character: a"
describe(S("hello")) // "starts with h, rest: ello"
Splitting and Joining
// Split
val parts = S("a,b,c").Split(",")
// parts == Array[Str]{S("a"), S("b"), S("c")}
// SplitAt
val (left, right) = S("hello").SplitAt(2)
// left.ToString() == "he", right.ToString() == "llo"
// Join
val joined = Join(ArrayOf(S("a"), S("b"), S("c")), "-")
// joined.ToString() == "a-b-c"
// Lines
val lines = S("line1\nline2\nline3").Lines()
// lines.Length() == 3
// Words
val words = S("hello world\tfoo").Words()
// words.Length() == 3
Padding
S("42").PadLeft(5, rune(48)) // "00042" (pad with '0')
S("hi").PadRight(5, rune(45)) // "hi---" (pad with '-')
S("a").Center(5, rune(45)) // "--a--"
StringBuilder
StringBuilder is a mutable string builder for efficient string concatenation, following the same mutable pattern as collection_mutable.
Construction
val sb = NewStringBuilder() // empty
val sb2 = NewStringBuilderFrom(S("hello")) // from Str
val sb3 = NewStringBuilderFromString("hello") // from Go string
Appending (Chainable)
All append methods return *StringBuilder for chaining:
// Str-based (primary API)
sb.Append(S("hello")) // append Str
sb.AppendLine(S("hello")) // append Str + newline
sb.AppendRune('*') // append single rune
// Go string-based (secondary API)
sb.AppendString("hello") // append Go string
sb.AppendStringLine("hello") // append Go string + newline
// Chaining
val result = NewStringBuilder()
.AppendString("hello")
.AppendString(" ")
.AppendString("world")
.ToString() // "hello world"
Output
sb.ToStr() // returns Str (primary)
sb.ToString() // returns Go string
sb.String() // Go Stringer interface
State
sb.Length() // byte length
sb.RuneCount() // character count
sb.IsEmpty() // true if no content
sb.NonEmpty() // true if has content
sb.Reset() // clears content
Performance Benchmarks
Benchmark results comparing GALA Str to Go native string operations on a 1,000-character ASCII string.
Running the Benchmarks
# GALA Str benchmark
bazel run //string_utils:perf_gala
# Go native benchmark
bazel run //string_utils:perf_go
Lazy rune array is only evaluated when functional operations (Map, Filter, CharAt, etc.) are called. Once evaluated, the result is cached for subsequent calls.
18 str-only methods (Contains, StartsWith, ToUpper, Split, etc.) never trigger rune conversion. Only 28 rune-accessing methods (Map, Filter, CharAt, Reverse, etc.) evaluate the lazy on first use.
Construction strategies:
strFromString(s) — defers rune conversion via lazy.New
strFromRunes(runes) — already-evaluated via lazy.Of
String-based ops (ToUpper, Trim, etc.) — return new Str with deferred runes