Fluent string helpers for Go.
str wraps a Go string so cleanup and transformation steps can be chained from left to right. Standard-named operations follow Go's strings contracts, including byte indexes, empty searches, and iterators. Application helpers such as Slice, Take, and padding remain rune-based.
Requires Go 1.24 or newer. Version 3 changes existing signatures and behavior; see the v2 to v3 migration guide.
go get github.com/goforj/str/v3package main
import (
"fmt"
"github.com/goforj/str/v3"
)
func main() {
result := str.Of(" welcome_to_go ").TrimSpace().Headline().String()
fmt.Println(result) // Welcome to Go
}str keeps the API deliberately small. These rules decide what belongs:
- Chains come first. Start with
str.Oforstr.Join. Methods that change text return a newstr.String, so the chain can continue. Checks, counts, parsers, and splits return ordinary Go values. - One job, one name. There are no aliases or compatibility shims. If two names mean the same thing, keep the clearer one.
- Preserve Go's contracts. Standard-named operations retain argument order and behavior. The source string becomes the receiver and a single string result becomes
String; multiple results, slices, and iterators retain their standard types.Join(elements, sep)starts a chain. - Keep units explicit.
Index,LastIndex, and the other standard index operations return byte offsets. Application helpers such asSlice,Take, and padding use runes. Never pass a byte index directly to a rune-based helper. - Preserve edge cases. Standard searches match empty strings, empty replacement searches insert at UTF-8 boundaries, and negative
Repeatcounts panic. Parsers and pattern operations return errors as documented. - Keep the scope clear. The Go 1.27 string-function surface is available on Go 1.24, including a
CutLastbackport. Statefulstrings.Builder,strings.Reader, andstrings.Replacerremain in the standard library. Additional helpers solve common application problems. - Examples must keep working. Every public operation has a generated example, and the test suite runs each one and checks its output.
Often, you should. Go's strings, unicode, strconv, and regexp packages are the right choice when you only need one or two operations. This is already clear:
username := strings.ToLower(strings.TrimSpace(" GoForj_Admin "))
// goforj_adminThe same cleanup with str reads from left to right:
username := str.Of(" GoForj_Admin ").TrimSpace().ToLower().String()
// goforj_adminEither version is reasonable. The difference is easier to see when more rules belong together.
Using the standard library:
func configKey(name string) string {
key := strings.TrimSpace(name)
key = strings.ToUpper(key)
key = strings.ReplaceAll(key, "-", "_")
key = strings.Trim(key, "_")
if !strings.HasPrefix(key, "APP_") {
key = "APP_" + key
}
return key
}
// configKey(" --billing-worker-- ") == "APP_BILLING_WORKER"Using str:
func configKey(name string) string {
return str.Of(name).
TrimSpace().
ToUpper().
ReplaceAll("-", "_").
Trim("_").
EnsurePrefix("APP_").
String()
}
// configKey(" --billing-worker-- ") == "APP_BILLING_WORKER"Some jobs do not have a single standard library call. For example, Slug handles case, punctuation, repeated separators, and Unicode letters. It can be one step in a longer chain that turns a report title into a CSV filename with a 64-rune base name:
func exportFilename(reportTitle string) string {
return str.Of(reportTitle).
ReplaceAll("&", "and").
Slug().
Take(64).
Trim("-").
EnsurePrefix("report-").
EnsureSuffix(".csv").
String()
}
filename := exportFilename("Q3 Sales & Returns - North America")
// report-q3-sales-and-returns-north-america.csvstr uses the standard library underneath and has no dependencies. Use whichever version makes the rules easiest to see.
These comparisons measure equivalent standard-library and str operations. Each cell reports the median of 10 samples as ns/op · B/op · allocs/op.
Recorded with go1.27.0 on linux/arm64 using -cpu=1 (GOMAXPROCS=1).
| Workload | Standard library | str chain |
|---|---|---|
| TrimSpace | 3.2 ns/op · 0 B/op · 0 allocs/op | 3.2 ns/op · 0 B/op · 0 allocs/op |
| ToLower | 64.4 ns/op · 32 B/op · 1 allocs/op | 65.6 ns/op · 32 B/op · 1 allocs/op |
| NormalizeSpace (Fields + Join) | 208.8 ns/op · 208 B/op · 2 allocs/op | 188.1 ns/op · 80 B/op · 1 allocs/op |
| TrimSpace → ToLower | 66.9 ns/op · 32 B/op · 1 allocs/op | 69.2 ns/op · 32 B/op · 1 allocs/op |
| ReplaceAll × 3 | 131.6 ns/op · 96 B/op · 3 allocs/op | 144.1 ns/op · 96 B/op · 3 allocs/op |
Timing is machine-specific; use it to understand the scale of these operations, not as a universal speed claim. Treat small timing differences within the raw sample spread as noise. Allocation counts are less sensitive to machine speed and show how much heap work each composition performs. In these workloads, wrapping and unwrapping added no heap allocations; allocations came from transformations that produced new text. NormalizeSpace is algorithmically different: the standard-library composition builds a field slice before joining it, while str uses one builder pass.
The benchmark source and committed raw output record exactly what ran, including the Go version and command. Refresh the measurements explicitly with go -C docs run ./readme -record-benchmarks; ordinary README generation only renders that frozen snapshot.
The full API and these examples are also available on pkg.go.dev.
These examples come from GoDoc and run as part of the test suite.
EnsurePrefix ensures the string starts with prefix, adding it if missing. Similar: EnsureSuffix and TrimPrefix.
v := str.Of("path/to").EnsurePrefix("/").String()
println(v)
// #string /path/toEnsureSuffix ensures the string ends with suffix, adding it if missing. Similar: EnsurePrefix and TrimSuffix.
v := str.Of("path/to").EnsureSuffix("/").String()
println(v)
// #string path/to/TrimPrefix removes prefix when it appears at the start of the string. Similar: TrimSuffix and EnsurePrefix.
v := str.Of("https://goforj.dev").TrimPrefix("https://").String()
println(v)
// #string goforj.devTrimSuffix removes suffix when it appears at the end of the string. Similar: TrimPrefix and EnsureSuffix.
v := str.Of("file.txt").TrimSuffix(".txt").String()
println(v)
// #string fileUnwrap removes matching before and after strings if present. Similar: Wrap.
v := str.Of(`"GoForj"`).Unwrap(`"`, `"`).String()
println(v)
// #string GoForjWrap surrounds the string with before and after. Similar: Unwrap.
v := str.Of("GoForj").Wrap(`"`, `"`).String()
println(v)
// #string "GoForj"Camel converts the string to camelCase. Similar: Pascal.
v := str.Of("foo_bar baz").Camel().String()
println(v)
// #string fooBarBazHeadline converts the string into a human-friendly headline: splits on case/underscores/dashes/whitespace, title-cases words, and lowercases small words (except the first). Similar: Title.
v := str.Of("emailNotification_sent").Headline().String()
println(v)
// #string Email Notification SentKebab converts the string to kebab-case. Similar: Snake.
v := str.Of("fooBar baz").Kebab().String()
println(v)
// #string foo-bar-bazLcFirst returns the string with the first rune lower-cased. Similar: UcFirst and ToLower.
v := str.Of("Gopher").LcFirst().String()
fmt.Println(v)
// #string gopherPascal converts the string to PascalCase. Similar: Camel.
v := str.Of("foo_bar baz").Pascal().String()
fmt.Println(v)
// #string FooBarBazSnake converts the string to snake_case. Similar: Kebab.
v := str.Of("fooBar baz").Snake().String()
println(v)
// #string foo_bar_bazTitle title-cases word-initial letters using strings.Title, preserving other letters.
Deprecated: Like strings.Title, its word boundaries do not handle Unicode punctuation properly. Use golang.org/x/text/cases for linguistic title casing.
v := str.Of("hello WORLD").Title().String()
println(v)
// #string Hello WORLDToLower returns a lowercase copy of the string using Unicode rules. Similar: ToUpper and LcFirst.
v := str.Of("GoLang").ToLower().String()
println(v)
// #string golangToLowerSpecial maps every rune to lowercase using c's language-specific case rules.
v := str.Of("I").ToLowerSpecial(unicode.TurkishCase).String()
println(v)
// #string ıToTitle maps every rune to Unicode titlecase.
v := str.Of("go").ToTitle().String()
println(v)
// #string GOToTitleSpecial maps every rune to Unicode titlecase using c's language-specific case rules.
v := str.Of("i").ToTitleSpecial(unicode.TurkishCase).String()
println(v)
// #string İToUpper returns an uppercase copy of the string using Unicode rules. Similar: ToLower and UcFirst.
v := str.Of("GoLang").ToUpper().String()
println(v)
// #string GOLANGToUpperSpecial maps every rune to uppercase using c's language-specific case rules.
v := str.Of("i").ToUpperSpecial(unicode.TurkishCase).String()
println(v)
// #string İUcFirst returns the string with the first rune upper-cased. Similar: LcFirst and ToUpper.
v := str.Of("gopher").UcFirst().String()
println(v)
// #string GopherIsASCII reports whether the string consists solely of 7-bit ASCII runes.
v := str.Of("gopher").IsASCII()
println(v)
// #bool trueIsAlnum reports whether the string contains at least one rune and every rune is a Unicode letter or number.
v := str.Of("Gopher2025").IsAlnum()
println(v)
// #bool trueIsAlpha reports whether the string contains at least one rune and every rune is a Unicode letter.
v := str.Of("Gopher").IsAlpha()
println(v)
// #bool trueIsBlank reports whether the string contains only Unicode whitespace. Similar: IsEmpty.
v := str.Of(" \t\n")
println(v.IsBlank())
// #bool trueIsEmpty reports whether the string has zero length. Similar: IsBlank.
v := str.Of("").IsEmpty()
println(v)
// #bool trueIsNumeric reports whether the string contains at least one rune and every rune is a Unicode number.
v := str.Of("12345").IsNumeric()
println(v)
// #bool trueDeduplicate collapses consecutive instances of char into a single instance. If char is zero, space is used. Similar: NormalizeSpace.
v := str.Of("The Go Playground").Deduplicate(' ').String()
println(v)
// #string The Go PlaygroundNormalizeNewlines replaces CRLF, CR, and Unicode separators with \n. Similar: Lines.
v := str.Of("a\r\nb\u2028c").NormalizeNewlines().String()
println(v)
// #string a\nb\ncNormalizeSpace removes surrounding whitespace and collapses internal whitespace to single spaces. Similar: TrimSpace.
v := str.Of(" go forj ").NormalizeSpace().String()
println(v)
// #string go forjTrim removes leading and trailing runes contained in cutset.
v := str.Of("..GoForj!!").Trim(".!").String()
println(v)
// #string GoForjTrimFunc removes leading and trailing runes satisfying f.
v := str.Of("12Go34").TrimFunc(unicode.IsDigit).String()
println(v)
// #string GoTrimLeft removes leading runes contained in cutset.
v := str.Of("..GoForj!!").TrimLeft(".!").String()
println(v)
// #string GoForj!!TrimLeftFunc removes leading runes satisfying f.
v := str.Of("12Go34").TrimLeftFunc(unicode.IsDigit).String()
println(v)
// #string Go34TrimRight removes trailing runes contained in cutset.
v := str.Of("..GoForj!!").TrimRight(".!").String()
println(v)
// #string ..GoForjTrimRightFunc removes trailing runes satisfying f.
v := str.Of("12Go34").TrimRightFunc(unicode.IsDigit).String()
println(v)
// #string 12GoTrimSpace removes leading and trailing Unicode whitespace.
v := str.Of(" GoForj ").TrimSpace().String()
println(v)
// #string GoForjEqualFold reports whether the string matches other using Unicode simple case folding.
v := str.Of("gopher").EqualFold("GOPHER")
println(v)
// #bool trueAppend concatenates the provided parts to the end of the string. Similar: Prepend.
v := str.Of("Go").Append("Forj", "!").String()
println(v)
// #string GoForj!Prepend concatenates the provided parts to the beginning of the string. Similar: Append.
v := str.Of("World").Prepend("Hello ", "Go ").String()
println(v)
// #string Hello Go WorldOf wraps a raw string with fluent helpers.
v := str.Of("gopher")
println(v.String())
// #string gopherBool parses the string as a bool using strconv.ParseBool semantics. Similar: Int and Float64.
v, err := str.Of("true").Bool()
println(v, err == nil)
// #bool true
// #bool trueFloat64 parses the string as a float64 using strconv.ParseFloat semantics. Similar: Bool and Int.
v, err := str.Of("3.14").Float64()
fmt.Println(v, err == nil)
// #float64 3.14
// #bool trueInt parses the string as a base-10 int using strconv.Atoi semantics. Similar: Bool and Float64.
v, err := str.Of("42").Int()
println(v, err == nil)
// #int 42
// #bool trueFromBase64 decodes a standard Base64 string. Similar: ToBase64.
v, err := str.Of("Z29waGVy").FromBase64()
println(v.String(), err == nil)
// #string gopher
// #bool trueToBase64 encodes the string using standard Base64. Similar: FromBase64.
v := str.Of("gopher").ToBase64().String()
println(v)
// #string Z29waGVyGoString allows %#v formatting to print the raw string.
v := str.Of("go")
println(fmt.Sprintf("%#v", v))
// #string goString returns the underlying raw string value.
v := str.Of("go").String()
println(v)
// #string goRuneCount returns the number of Unicode code points in the string.
v := str.Of("gophers 🦫").RuneCount()
println(v)
// #int 9Mask replaces the middle of the string with the given rune, revealing revealLeft runes at the start and revealRight runes at the end. Negative reveal values count from the end. If the reveal counts cover the whole string, the original string is returned.
v := str.Of("gopher@example.com").Mask('*', 3, 4).String()
println(v)
// #string gop***********.comMatch reports whether the entire string matches pattern using [path.Match] syntax. A malformed pattern returns an error, and wildcards do not match a slash.
matched, err := str.Of("billing:reports").Match("billing:*")
println(matched, err == nil)
// #bool true
// #bool truePadBoth pads the string on both sides to reach length runes using pad (defaults to space). Widths at or below the current rune width leave the string unchanged. Similar: PadLeft and PadRight.
v := str.Of("go").PadBoth(6, "-").String()
println(v)
// #string --go--PadLeft pads the string on the left to reach length runes using pad (defaults to space). Widths at or below the current rune width leave the string unchanged. Similar: PadRight and PadBoth.
v := str.Of("go").PadLeft(5, " ").String()
println(v)
// #string \u0020\u0020\u0020goPadRight pads the string on the right to reach length runes using pad (defaults to space). Widths at or below the current rune width leave the string unchanged. Similar: PadLeft and PadBoth.
v := str.Of("go").PadRight(5, ".").String()
println(v)
// #string go...Plural returns a best-effort English plural form of the final identifier word. It handles common English forms and identifier boundaries without claiming to resolve every irregular or ambiguous noun. Similar: Singular.
v := str.Of("city").Plural().String()
println(v)
// #string citiesSingular returns a best-effort English singular form of the final identifier word. It handles common English forms and identifier boundaries without claiming to resolve every irregular or ambiguous noun. Similar: Plural.
v := str.Of("people").Singular().String()
println(v)
// #string personRemove deletes all occurrences of provided substrings.
v := str.Of("The Go Toolkit").Remove("Go ").String()
println(v)
// #string The ToolkitReplace replaces the first n non-overlapping occurrences of old with new. A negative n replaces all matches; zero leaves the string unchanged. An empty old matches at the beginning and after each UTF-8 sequence.
v := str.Of("go go go").Replace("go", "Go", 2).String()
println(v)
// #string Go Go goReplaceAll replaces all non-overlapping occurrences of old with new. An empty old matches at the beginning and after each UTF-8 sequence.
v := str.Of("go gopher go").ReplaceAll("go", "Go").String()
println(v)
// #string Go Gopher GoReplaceArray replaces all occurrences of each old in olds with repl. Entries are applied sequentially, including replacements produced by earlier entries. Empty entries insert repl at UTF-8 boundaries, like ReplaceAll. Similar: ReplaceAll and Swap.
v := str.Of("The---Go---Toolkit")
println(v.ReplaceArray([]string{"---"}, "-").String())
// #string The-Go-ToolkitReplaceFirst replaces the first occurrence of old with repl. An empty old inserts repl at the beginning. Similar: ReplaceLast and ReplaceAll.
v := str.Of("gopher gopher").ReplaceFirst("gopher", "go").String()
println(v)
// #string go gopherReplaceFold replaces all non-overlapping occurrences of old with repl using Unicode simple case folding. An empty old inserts repl at UTF-8 boundaries, like ReplaceAll. Similar: ReplaceAll.
v := str.Of("go gopher GO").ReplaceFold("GO", "Go").String()
println(v)
// #string Go Gopher GoReplaceLast replaces the last occurrence of old with repl. An empty old inserts repl at the end. Similar: ReplaceFirst and ReplaceAll.
v := str.Of("gopher gopher").ReplaceLast("gopher", "go").String()
println(v)
// #string gopher goReplacePrefix replaces old with repl when old is a prefix of the string. An empty old inserts repl at the beginning. Similar: ReplaceSuffix and TrimPrefix.
v := str.Of("prefix-value").ReplacePrefix("prefix-", "new-").String()
println(v)
// #string new-valueReplaceSuffix replaces old with repl when old is a suffix of the string. An empty old inserts repl at the end. Similar: ReplacePrefix and TrimSuffix.
v := str.Of("file.old").ReplaceSuffix(".old", ".new").String()
println(v)
// #string file.newSwap replaces multiple values in one pass using strings.Replacer built from a map. Longer keys take priority at the same position; replacements are not rescanned. Empty keys follow strings.Replacer byte boundaries and can split a multibyte UTF-8 rune. Use ReplaceAll for empty-search insertion at UTF-8 sequence boundaries. Similar: ReplaceArray.
pairs := map[string]string{"Gophers": "GoForj", "are": "is", "great": "fantastic"}
v := str.Of("Gophers are great!").Swap(pairs).String()
println(v)
// #string GoForj is fantastic!Compare returns -1, 0, or 1 according to lexicographic byte order.
v := str.Of("go").Compare("rust")
println(v)
// #int -1Contains reports whether the string contains sub using a case-sensitive comparison. An empty substring always matches. Similar: ContainsFold.
v := str.Of("Go means gophers").Contains("gopher")
println(v)
// #bool trueContainsAny reports whether any rune in chars occurs in the string.
v := str.Of("gopher").ContainsAny("aeiou")
println(v)
// #bool trueContainsFold reports whether the string contains sub using Unicode simple case folding. An empty substring always matches. Similar: Contains.
v := str.Of("Go means gophers").ContainsFold("GOPHER")
println(v)
// #bool trueContainsFunc reports whether any rune satisfies f.
v := str.Of("go2").ContainsFunc(unicode.IsDigit)
println(v)
// #bool trueContainsRune reports whether r occurs in the string.
v := str.Of("café").ContainsRune('é')
println(v)
// #bool trueCount counts non-overlapping occurrences of sub. An empty sub matches at the beginning and after each UTF-8 sequence.
v := str.Of("gogophergo").Count("go")
println(v)
// #int 3HasPrefix reports whether the string starts with prefix using a case-sensitive comparison. An empty prefix always matches. Similar: HasPrefixFold and HasSuffix.
v := str.Of("gopher").HasPrefix("go")
println(v)
// #bool trueHasPrefixFold reports whether the string starts with prefix using Unicode simple case folding. An empty prefix always matches. Similar: HasPrefix and HasSuffixFold.
v := str.Of("gopher").HasPrefixFold("GO")
println(v)
// #bool trueHasSuffix reports whether the string ends with suffix using a case-sensitive comparison. An empty suffix always matches. Similar: HasSuffixFold and HasPrefix.
v := str.Of("gopher").HasSuffix("her")
println(v)
// #bool trueHasSuffixFold reports whether the string ends with suffix using Unicode simple case folding. An empty suffix always matches. Similar: HasSuffix and HasPrefixFold.
v := str.Of("gopher").HasSuffixFold("HER")
println(v)
// #bool trueIndex returns the byte index of the first occurrence of sub, or -1 if not found. Similar: LastIndex.
v := str.Of("héllo").Index("llo")
println(v)
// #int 3IndexAny returns the byte offset of the first rune in chars, or -1 if absent.
v := str.Of("go").IndexAny("o")
println(v)
// #int 1IndexByte returns the byte offset of the first byte equal to c, or -1 if absent.
v := str.Of("go").IndexByte('o')
println(v)
// #int 1IndexFunc returns the byte offset of the first rune satisfying f, or -1 if absent.
v := str.Of("go2").IndexFunc(unicode.IsDigit)
println(v)
// #int 2IndexRune returns the byte offset of the first rune equal to r, or -1 if absent.
v := str.Of("go").IndexRune('o')
println(v)
// #int 1LastIndex returns the byte index of the last occurrence of sub, or -1 if not found. Similar: Index.
v := str.Of("go gophers go").LastIndex("go")
println(v)
// #int 11LastIndexAny returns the byte offset of the last rune in chars, or -1 if absent.
v := str.Of("go").LastIndexAny("o")
println(v)
// #int 1LastIndexByte returns the byte offset of the last byte equal to c, or -1 if absent.
v := str.Of("go").LastIndexByte('o')
println(v)
// #int 1LastIndexFunc returns the byte offset of the last rune satisfying f, or -1 if absent.
v := str.Of("go2").LastIndexFunc(unicode.IsDigit)
println(v)
// #int 2Slug returns a lowercase Unicode slug separated by hyphens. Unicode letters and digits are preserved, while every other run is collapsed to one hyphen. Similar: Kebab.
v := str.Of("Go Forj Toolkit").Slug().String()
println(v)
// #string go-forj-toolkitExcerpt returns a snippet around the first occurrence of needle with the given radius. If needle is not found, an empty string is returned. If radius <= 0, a default of 100 is used. Omission is used at the start/end when text is trimmed (default "...").
v := str.Of("This is my name").Excerpt("my", 3, "...")
println(v.String())
// #string ...is my na...Fields splits the string into fields separated by Unicode whitespace. Consecutive separators are combined; empty or separator-only input yields no fields.
v := str.Of("a b c").Fields()
fmt.Println(v)
// #[]string [a b c]FieldsFunc splits the string into fields separated by runes satisfying f. The predicate must return the same result for a given rune; its call order is unspecified. Consecutive separators are combined; empty or separator-only input yields no fields.
v := str.Of("a b c").FieldsFunc(unicode.IsSpace)
fmt.Println(v)
// #[]string [a b c]FieldsFuncSeq returns an iterator over fields separated by runes satisfying f. Each iteration starts again from the beginning of the string. The predicate must return the same result for a given rune; its call order is unspecified. Consecutive separators are combined; empty or separator-only input yields no fields.
v := slices.Collect(str.Of("a b c").FieldsFuncSeq(unicode.IsSpace))
fmt.Println(v)
// #[]string [a b c]FieldsSeq returns an iterator over fields separated by Unicode whitespace. Each iteration starts again from the beginning of the string. Consecutive separators are combined; empty or separator-only input yields no fields.
v := slices.Collect(str.Of("a b c").FieldsSeq())
fmt.Println(v)
// #[]string [a b c]Lines returns a single-use iterator over newline-terminated lines. Newline bytes are retained; empty input yields no lines and a trailing newline does not produce an extra empty line. Use NormalizeNewlines().Split("\n") when normalized, delimiter-free fields are wanted.
v := slices.Collect(str.Of("a\nb").Lines())
fmt.Printf("%q\n", v)
// #[]string ["a\\n" "b"]Split splits the string by the given separator.
v := str.Of("a,b,c").Split(",")
fmt.Println(v)
// #[]string [a b c]SplitAfter returns substrings including their trailing separator. An empty sep splits after each UTF-8 sequence.
v := str.Of("a,b,c").SplitAfter(",")
fmt.Println(v)
// #[]string [a, b, c]SplitAfterN returns substrings including their trailing separator. A positive n limits the result to n substrings; zero returns nil and negative n has no limit. An empty sep splits after each UTF-8 sequence.
v := str.Of("a,b,c").SplitAfterN(",", 2)
fmt.Println(v)
// #[]string [a, b,c]SplitAfterSeq returns a single-use iterator over substrings including their trailing separator. An empty sep splits after each UTF-8 sequence.
v := slices.Collect(str.Of("a,b,c").SplitAfterSeq(","))
fmt.Println(v)
// #[]string [a, b, c]SplitN returns substrings separated by sep. A positive n limits the result to n substrings; zero returns nil and negative n has no limit. An empty sep splits after each UTF-8 sequence.
v := str.Of("a,b,c").SplitN(",", 2)
fmt.Println(v)
// #[]string [a b,c]SplitSeq returns a single-use iterator over substrings separated by sep. An empty sep splits after each UTF-8 sequence.
v := slices.Collect(str.Of("a,b,c").SplitSeq(","))
fmt.Println(v)
// #[]string [a b c]After returns the substring after the first occurrence of sep. If sep is empty or not found, the original string is returned. Similar: AfterLast and Before.
v := str.Of("gopher::go").After("::").String()
println(v)
// #string goAfterLast returns the substring after the last occurrence of sep. If sep is empty or not found, the original string is returned. Similar: After and BeforeLast.
v := str.Of("pkg/path/file.txt").AfterLast("/").String()
println(v)
// #string file.txtBefore returns the substring before the first occurrence of sep. If sep is empty or not found, the original string is returned. Similar: BeforeLast and After.
v := str.Of("gopher::go").Before("::").String()
println(v)
// #string gopherBeforeLast returns the substring before the last occurrence of sep. If sep is empty or not found, the original string is returned. Similar: Before and AfterLast.
v := str.Of("pkg/path/file.txt").BeforeLast("/").String()
println(v)
// #string pkg/pathBetween returns the substring between the first start marker and the first end marker after it. It returns an empty string when either marker is empty or missing.
v := str.Of("[first] and [second]").Between("[", "]").String()
println(v)
// #string firstCharAt returns the rune at the given index and true if within bounds. Similar: Slice and RuneCount.
v, ok := str.Of("gopher").CharAt(2)
println(string(v), ok)
// #string p
// #bool trueCommonPrefix returns the longest shared prefix between the string and all provided others. Comparison is rune-safe. If no others are provided, the original string is returned. Similar: CommonSuffix.
v := str.Of("gopher").CommonPrefix("go", "gold").String()
println(v)
// #string goCommonSuffix returns the longest shared suffix between the string and all provided others. Comparison is rune-safe. If no others are provided, the original string is returned. Similar: CommonPrefix.
v := str.Of("main_test.go").CommonSuffix("user_test.go", "api_test.go").String()
println(v)
// #string _test.goCut splits around the first occurrence of sep. An empty sep is a match. On no match it returns the original string, "", false.
before, after, found := str.Of("go:forj").Cut(":")
fmt.Println(before, after, found)
// #string go forj trueCutLast splits around the last occurrence of sep. An empty sep is a match. On no match it returns the original string, "", false. CutLast preserves the Go 1.27 contract without raising the Go 1.24 minimum.
before, after, found := str.Of("go:forj").CutLast(":")
fmt.Println(before, after, found)
// #string go forj trueCutPrefix removes prefix and reports whether it was present. An empty prefix is a match.
value, found := str.Of("go:forj").CutPrefix("go:")
fmt.Println(value, found)
// #string forj trueCutSuffix removes suffix and reports whether it was present. An empty suffix is a match.
value, found := str.Of("go:forj").CutSuffix(":forj")
fmt.Println(value, found)
// #string go trueLimit truncates the string to length runes, appending suffix if truncation occurs.
v := str.Of("Perfectly balanced, as all things should be.").Limit(10, "...").String()
println(v)
// #string Perfectly\u0020...Slice returns the substring between rune offsets [start:end). Index and LastIndex return bytes, which must not be passed directly here. Indices are clamped; if start >= end the result is empty.
v := str.Of("naïve café").Slice(3, 7).String()
println(v)
// #string ve cSubstrReplace replaces the rune slice in [start:end) with repl.
v := str.Of("naïve café").SubstrReplace("i", 2, 3).String()
println(v)
// #string naive caféTake returns the first length runes of the string (clamped). Similar: TakeLast and Limit.
v := str.Of("gophers").Take(3).String()
println(v)
// #string gopTakeLast returns the last length runes of the string (clamped). Similar: Take.
v := str.Of("gophers").TakeLast(4).String()
println(v)
// #string hersClone copies the underlying bytes into a fresh allocation. Use it to release a large backing string retained by a small substring. Empty input returns an empty string without allocating.
v := str.Of("gopher").Clone().String()
println(v)
// #string gopherMap maps each rune using mapping, dropping runes mapped to a negative value.
v := str.Of("go").Map(unicode.ToUpper).String()
println(v)
// #string GORepeat repeats the string count times. It panics if count is negative or the result length overflows int.
v := str.Of("go").Repeat(3).String()
println(v)
// #string gogogoReverse returns a rune-safe reversed string.
v := str.Of("naïve").Reverse().String()
println(v)
// #string evïanToValidUTF8 replaces each run of invalid UTF-8 bytes with replacement.
v := str.Of("a\xff\xfeb").ToValidUTF8("?").String()
println(v)
// #string a?bFirstWord returns the first detected word or an empty string. Similar: LastWord and SplitWords.
v := str.Of("Hello world")
println(v.FirstWord().String())
// #string HelloInitials returns the uppercase first rune of each detected word. Words are split the same way as SplitWords, including camel case and acronym boundaries. Similar: SplitWords.
v := str.Of("portableNetwork graphics").Initials().String()
println(v)
// #string PNGJoin concatenates elements with sep and returns the result to the fluent chain. Join starts a chain from a slice without discarding an existing receiver. Similar: Split.
v := str.Join([]string{"foo", "bar"}, "-").String()
println(v)
// #string foo-barLastWord returns the last detected word or an empty string. Similar: FirstWord and SplitWords.
v := str.Of("Hello world").LastWord().String()
println(v)
// #string worldSplitWords splits the string into Unicode words, including camel case and acronym boundaries. Similar: FirstWord, LastWord, WordCount, and Words.
v := str.Of("one, two, three").SplitWords()
fmt.Println(v)
// #[]string [one two three]WordCount returns the number of detected words. Similar: SplitWords.
v := str.Of("Hello, world!").WordCount()
println(v)
// #int 2Words limits the string to count words, preserving the source through the selected word boundary and appending suffix if truncated. Similar: SplitWords and WrapWords.
v := str.Of("Perfectly balanced, as all things should be.").Words(3, " >>>").String()
println(v)
// #string Perfectly balanced, as >>>WrapWords wraps the string to the given rune width on whitespace boundaries, using breakStr between lines without discarding punctuation. Similar: Words.
v := str.Of("The quick brown fox jumped over the lazy dog.").WrapWords(20, "\n").String()
println(v)
// #string The quick brown fox\njumped over the lazy\ndog.- API documentation and examples
- v2 to v3 migration guide
- Standard API contract
- Historical v1 to v2 migration guide
- Report a bug or request a feature
docs and examples are separate Go modules, keeping their tooling and generated programs out of the library module download.
Use make test, make test-race, make vet, and make generate. The test and vet targets cover all three modules; generation rebuilds the examples and README.
Licensed under the MIT License.
