README.md
March 10, 2026 · View on GitHub
A fluent, Laravel-inspired string toolkit for Go, focused on rune-safe helpers, expressive transformations, and predictable behavior beyond the standard library.
Installation
go get github.com/goforj/str
Runnable examples
Every function has a corresponding runnable example under ./examples.
These examples are generated directly from the documentation blocks of each function, ensuring the docs and code never drift. These are the same examples you see here in the README and GoDoc.
An automated test executes every example to verify it builds and runs successfully.
This guarantees all examples are valid, up-to-date, and remain functional as the API evolves.
API Index
Affixes
ChopEnd
ChopEnd removes the first matching suffix if present.
v := str.Of("file.txt").ChopEnd(".txt", ".md").String()
println(v)
// #string file
ChopStart
ChopStart removes the first matching prefix if present.
v := str.Of("https://goforj.dev").ChopStart("https://", "http://").String()
println(v)
// #string goforj.dev
EnsurePrefix
EnsurePrefix ensures the string starts with prefix, adding it if missing.
v := str.Of("path/to").EnsurePrefix("/").String()
println(v)
// #string /path/to
EnsureSuffix
EnsureSuffix ensures the string ends with suffix, adding it if missing.
v := str.Of("path/to").EnsureSuffix("/").String()
println(v)
// #string path/to/
HasSurrounding
HasSurrounding reports whether the string starts with before and ends with after. If after is empty, before is used for both sides.
v := str.Of(`"GoForj"`).HasSurrounding(`"`, "")
println(v)
// #bool true
Unwrap
Unwrap removes matching before and after strings if present.
v := str.Of(`"GoForj"`).Unwrap(`"`, `"`).String()
println(v)
// #string GoForj
Wrap
Wrap surrounds the string with before and after (after defaults to before).
v := str.Of("GoForj").Wrap(`"`, "").String()
println(v)
// #string "GoForj"
Case
Camel
Camel converts the string to camelCase.
v := str.Of("foo_bar baz").Camel().String()
println(v)
// #string fooBarBaz
Headline
Headline converts the string into a human-friendly headline: splits on case/underscores/dashes/whitespace, title-cases words, and lowercases small words (except the first).
v := str.Of("emailNotification_sent").Headline().String()
println(v)
// #string Email Notification Sent
Kebab
Kebab converts the string to kebab-case.
v := str.Of("fooBar baz").Kebab().String()
println(v)
// #string foo-bar-baz
LcFirst
LcFirst returns the string with the first rune lower-cased.
v := str.Of("Gopher").LcFirst().String()
fmt.Println(v)
// #string gopher
Pascal
Pascal converts the string to PascalCase.
v := str.Of("foo_bar baz").Pascal().String()
fmt.Println(v)
// #string FooBarBaz
Snake
Snake converts the string to snake_case using the provided separator (default "_").
v := str.Of("fooBar baz").Snake("_").String()
println(v)
// #string foo_bar_baz
Title
Title converts the string to title case (first letter of each word upper, rest lower) using Unicode rules.
v := str.Of("a nice title uses the correct case").Title().String()
println(v)
// #string A Nice Title Uses The Correct Case
ToLower
ToLower returns a lowercase copy of the string using Unicode rules.
v := str.Of("GoLang").ToLower().String()
println(v)
// #string golang
ToTitle
ToTitle returns a title-cased copy where all letters are mapped using Unicode title case.
v := str.Of("ß").ToTitle().String()
println(v)
// #string SS
ToUpper
ToUpper returns an uppercase copy of the string using Unicode rules.
v := str.Of("GoLang").ToUpper().String()
println(v)
// #string GOLANG
UcFirst
UcFirst returns the string with the first rune upper-cased.
v := str.Of("gopher").UcFirst().String()
println(v)
// #string Gopher
UcWords
UcWords uppercases the first rune of each word, leaving the rest unchanged. Words are sequences of letters/digits.
v := str.Of("hello WORLD").UcWords().String()
println(v)
// #string Hello WORLD
Checks
IsASCII
IsASCII reports whether the string consists solely of 7-bit ASCII runes.
v := str.Of("gopher").IsASCII()
println(v)
// #bool true
IsAlnum
IsAlnum 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 true
IsAlpha
IsAlpha reports whether the string contains at least one rune and every rune is a Unicode letter.
v := str.Of("Gopher").IsAlpha()
println(v)
// #bool true
IsBlank
IsBlank reports whether the string contains only Unicode whitespace.
v := str.Of(" \\t\\n")
println(v.IsBlank())
// #bool true
IsEmpty
IsEmpty reports whether the string has zero length.
v := str.Of("").IsEmpty()
println(v)
// #bool true
IsNumeric
IsNumeric reports whether the string contains at least one rune and every rune is a Unicode number.
v := str.Of("12345").IsNumeric()
println(v)
// #bool true
Cleanup
Deduplicate
Deduplicate collapses consecutive instances of char into a single instance. If char is zero, space is used.
v := str.Of("The Go Playground").Deduplicate(' ').String()
println(v)
// #string The Go Playground
NormalizeNewlines
NormalizeNewlines replaces CRLF, CR, and Unicode separators with \n.
v := str.Of("a\\r\\nb\\u2028c").NormalizeNewlines().String()
println(v)
// #string a\nb\nc
NormalizeSpace
NormalizeSpace collapses whitespace runs to single spaces without trimming ends.
v := str.Of(" go forj ").NormalizeSpace().String()
println(v)
// #string go forj
Squish
Squish trims leading/trailing whitespace and collapses internal whitespace to single spaces.
v := str.Of(" go forj ").Squish().String()
println(v)
// #string go forj
Trim
Trim trims leading and trailing characters. If cutset is the zero value (empty string), trims Unicode whitespace.
v := str.Of(" GoForj ").Trim("").String()
println(v)
// #string GoForj
TrimLeft
TrimLeft trims leading characters. If cutset is the zero value (empty string), trims Unicode whitespace.
v := str.Of(" GoForj ").TrimLeft("").String()
println(v)
// #string GoForj
TrimRight
TrimRight trims trailing characters. If cutset is the zero value (empty string), trims Unicode whitespace.
v := str.Of(" GoForj ").TrimRight("").String()
println(v)
// #string GoForj
TrimSpace
TrimSpace trims leading and trailing Unicode whitespace.
v := str.Of(" GoForj ").TrimSpace().String()
println(v)
// #string GoForj
Comparison
Equals
Equals reports whether the string exactly matches other (case-sensitive).
v := str.Of("gopher").Equals("gopher")
println(v)
// #bool true
EqualsFold
EqualsFold reports whether the string matches other using Unicode case folding.
v := str.Of("gopher").EqualsFold("GOPHER")
println(v)
// #bool true
Compose
Append
Append concatenates the provided parts to the end of the string.
v := str.Of("Go").Append("Forj", "!").String()
println(v)
// #string GoForj!
NewLine
NewLine appends a newline character to the string.
v := str.Of("hello").NewLine().Append("world").String()
println(v)
// #string hello\nworld
Prepend
Prepend concatenates the provided parts to the beginning of the string.
v := str.Of("World").Prepend("Hello ", "Go ").String()
println(v)
// #string Hello Go World
Constructor
Of
Of wraps a raw string with fluent helpers.
v := str.Of("gopher")
println(v.String())
// #string gopher
Conversion
Bool
Bool parses the string as a bool using strconv.ParseBool semantics.
v, err := str.Of("true").Bool()
println(v, err == nil)
// #bool true
// #bool true
Float64
Float64 parses the string as a float64 using strconv.ParseFloat semantics.
v, err := str.Of("3.14").Float64()
println(v, err == nil)
// #float64 3.14
// #bool true
Int
Int parses the string as a base-10 int using strconv.Atoi semantics.
v, err := str.Of("42").Int()
println(v, err == nil)
// #int 42
// #bool true
Encoding
FromBase64
FromBase64 decodes a standard Base64 string.
v, err := str.Of("Z29waGVy").FromBase64()
println(v.String(), err)
// #string gopher
// #error <nil>
ToBase64
ToBase64 encodes the string using standard Base64.
v := str.Of("gopher").ToBase64().String()
println(v)
// #string Z29waGVy
Fluent
GoString
GoString allows %#v formatting to print the raw string.
v := str.Of("go")
println(fmt.Sprintf("%#v", v))
// #string go
String
String returns the underlying raw string value.
v := str.Of("go").String()
println(v)
// #string go
Length
Len
Len returns the number of runes in the string.
v := str.Of("gophers 🦫").Len()
println(v)
// #int 9
RuneCount
RuneCount is an alias for Len to make intent explicit in mixed codebases.
v := str.Of("naïve").RuneCount()
println(v)
// #int 5
Masking
Mask
Mask 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***********.com
Match
Is
Is reports whether the string matches any of the provided wildcard patterns. Patterns use '*' as a wildcard. Case-sensitive.
v := str.Of("foo/bar").Is("foo/*")
println(v)
// #bool true
IsMatch
IsMatch reports whether the string matches the provided regular expression.
v := str.Of("abc123").IsMatch(regexp.MustCompile(`\d+`))
println(v)
// #bool true
Match
Match returns the first match and submatches for the pattern.
re := regexp.MustCompile(`g(o+)`)
v := str.Of("gooo").Match(re)
println(v)
// #[]string [gooo ooo]
MatchAll
MatchAll returns all matches and submatches for the pattern.
re := regexp.MustCompile(`go+`)
v := str.Of("go gopher gooo").MatchAll(re)
println(v)
// #[][]string [[go] [gooo]]
Padding
PadBoth
PadBoth pads the string on both sides to reach length runes using pad (defaults to space).
v := str.Of("go").PadBoth(6, "-").String()
println(v)
// #string --go--
PadLeft
PadLeft pads the string on the left to reach length runes using pad (defaults to space).
v := str.Of("go").PadLeft(5, " ").String()
println(v)
// #string \u00a0\u00a0\u00a0go
PadRight
PadRight pads the string on the right to reach length runes using pad (defaults to space).
v := str.Of("go").PadRight(5, ".").String()
println(v)
// #string go...
Pluralize
Plural
Plural returns a best-effort English plural form of the last word.
v := str.Of("city").Plural().String()
println(v)
// #string cities
Singular
Singular returns a best-effort English singular form of the last word.
v := str.Of("people").Singular().String()
println(v)
// #string person
Replace
Remove
Remove deletes all occurrences of provided substrings.
v := str.Of("The Go Toolkit").Remove("Go ").String()
println(v)
// #string The Toolkit
ReplaceAll
ReplaceAll replaces all occurrences of old with new in the string. If old is empty, the original string is returned unchanged.
v := str.Of("go gopher go").ReplaceAll("go", "Go").String()
println(v)
// #string Go Gopher Go
ReplaceArray
ReplaceArray replaces all occurrences of each old in olds with repl.
v := str.Of("The---Go---Toolkit")
println(v.ReplaceArray([]string{"---"}, "-").String())
// #string The-Go-Toolkit
ReplaceEnd
ReplaceEnd replaces old with repl at the end of the string, if present.
v := str.Of("file.old").ReplaceEnd(".old", ".new").String()
println(v)
// #string file.new
ReplaceFirst
ReplaceFirst replaces the first occurrence of old with repl.
v := str.Of("gopher gopher").ReplaceFirst("gopher", "go").String()
println(v)
// #string go gopher
ReplaceFirstFold
ReplaceFirstFold replaces the first occurrence of old with repl using Unicode case folding.
v := str.Of("go gopher GO").ReplaceFirstFold("GO", "Go").String()
println(v)
// #string Go gopher GO
ReplaceFold
ReplaceFold replaces all occurrences of old with repl using Unicode case folding.
v := str.Of("go gopher GO").ReplaceFold("GO", "Go").String()
println(v)
// #string Go Gopher Go
ReplaceLast
ReplaceLast replaces the last occurrence of old with repl.
v := str.Of("gopher gopher").ReplaceLast("gopher", "go").String()
println(v)
// #string gopher go
ReplaceLastFold
ReplaceLastFold replaces the last occurrence of old with repl using Unicode case folding.
v := str.Of("go gopher GO").ReplaceLastFold("GO", "Go").String()
println(v)
// #string go gopher Go
ReplaceMatches
ReplaceMatches applies repl to each regex match and returns the result.
re := regexp.MustCompile(`\d+`)
v := str.Of("Hello 123 World").ReplaceMatches(re, func(m string) string { return "[" + m + "]" }).String()
println(v)
// #string Hello [123] World
ReplaceStart
ReplaceStart replaces old with repl at the start of the string, if present.
v := str.Of("prefix-value").ReplaceStart("prefix-", "new-").String()
println(v)
// #string new-value
Swap
Swap replaces multiple values using strings.Replacer built from a map.
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!
Search
Contains
Contains reports whether the string contains any of the provided substrings (case-sensitive). Empty substrings return true to match strings.Contains semantics.
v := str.Of("Go means gophers").Contains("rust", "gopher")
println(v)
// #bool true
ContainsAll
ContainsAll reports whether the string contains all provided substrings (case-sensitive). Empty substrings are ignored.
v := str.Of("Go means gophers").ContainsAll("Go", "gopher")
println(v)
// #bool true
ContainsAllFold
ContainsAllFold reports whether the string contains all provided substrings, using Unicode case folding for comparisons. Empty substrings are ignored.
v := str.Of("Go means gophers").ContainsAllFold("go", "GOPHER")
println(v)
// #bool true
ContainsFold
ContainsFold reports whether the string contains any of the provided substrings, using Unicode case folding for comparisons. Empty substrings return true.
v := str.Of("Go means gophers").ContainsFold("GOPHER", "rust")
println(v)
// #bool true
Count
Count returns the number of non-overlapping occurrences of sub.
v := str.Of("gogophergo").Count("go")
println(v)
// #int 3
CountFold
CountFold returns the number of non-overlapping occurrences of sub using Unicode-aware case-insensitive comparison.
v := str.Of("GoGOgophergo").CountFold("go")
println(v)
// #int 4
EndsWith
EndsWith reports whether the string ends with any of the provided suffixes (case-sensitive).
v := str.Of("gopher").EndsWith("her", "cat")
println(v)
// #bool true
EndsWithFold
EndsWithFold reports whether the string ends with any of the provided suffixes using Unicode case folding.
v := str.Of("gopher").EndsWithFold("HER")
println(v)
// #bool true
Index
Index returns the rune index of the first occurrence of sub, or -1 if not found.
v := str.Of("héllo").Index("llo")
println(v)
// #int 2
IndexFold
IndexFold returns the rune index of the first occurrence of sub using Unicode-aware case-insensitive comparison, or -1 if not found.
v := str.Of("Go gopher GO").IndexFold("go")
println(v)
// #int 0
LastIndex
LastIndex returns the rune index of the last occurrence of sub, or -1 if not found.
v := str.Of("go gophers go").LastIndex("go")
println(v)
// #int 10
LastIndexFold
LastIndexFold returns the rune index of the last occurrence of sub using Unicode-aware case-insensitive comparison, or -1 if not found.
v := str.Of("Go gopher GO").LastIndexFold("go")
println(v)
// #int 10
StartsWith
StartsWith reports whether the string starts with any of the provided prefixes (case-sensitive).
v := str.Of("gopher").StartsWith("go", "rust")
println(v)
// #bool true
StartsWithFold
StartsWithFold reports whether the string starts with any of the provided prefixes using Unicode case folding.
v := str.Of("gopher").StartsWithFold("GO")
println(v)
// #bool true
Slug
Slug
Slug produces an ASCII slug using the provided separator (default "-"), stripping accents where possible. Not locale-aware; intended for identifiers/URLs.
v := str.Of("Go Forj Toolkit").Slug("-").String()
println(v)
// #string go-forj-toolkit
Snippet
Excerpt
Excerpt 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...
Split
Lines
Lines splits the string into lines after normalizing newline variants.
v := str.Of("a\\r\\nb\\nc").Lines()
println(v)
// #[]string [a b c]
Split
Split splits the string by the given separator.
v := str.Of("a,b,c").Split(",")
println(v)
// #[]string [a b c]
UcSplit
UcSplit splits the string on uppercase boundaries and delimiters, returning segments.
v := str.Of("HTTPRequestID").UcSplit()
println(v)
// #[]string [HTTP Request ID]
Substrings
After
After returns the substring after the first occurrence of sep. If sep is empty or not found, the original string is returned.
v := str.Of("gopher::go").After("::").String()
println(v)
// #string go
AfterFold
AfterFold returns the substring after the first occurrence of sep using Unicode-aware case-insensitive comparison. If sep is empty or not found, the original string is returned.
v := str.Of("gopher::GO-team").AfterFold("::go").String()
println(v)
// #string -team
AfterLast
AfterLast returns the substring after the last occurrence of sep. If sep is empty or not found, the original string is returned.
v := str.Of("pkg/path/file.txt").AfterLast("/").String()
println(v)
// #string file.txt
AfterLastFold
AfterLastFold returns the substring after the last occurrence of sep using Unicode-aware case-insensitive comparison. If sep is empty or not found, the original string is returned.
v := str.Of("pkg/Path/FILE.txt").AfterLastFold("/path/").String()
println(v)
// #string FILE.txt
Before
Before returns the substring before the first occurrence of sep. If sep is empty or not found, the original string is returned.
v := str.Of("gopher::go").Before("::").String()
println(v)
// #string gopher
BeforeFold
BeforeFold returns the substring before the first occurrence of sep using Unicode-aware case-insensitive comparison. If sep is empty or not found, the original string is returned.
v := str.Of("GoPHER::go").BeforeFold("::GO").String()
println(v)
// #string GoPHER
BeforeLast
BeforeLast returns the substring before the last occurrence of sep. If sep is empty or not found, the original string is returned.
v := str.Of("pkg/path/file.txt").BeforeLast("/").String()
println(v)
// #string pkg/path
BeforeLastFold
BeforeLastFold returns the substring before the last occurrence of sep using Unicode-aware case-insensitive comparison. If sep is empty or not found, the original string is returned.
v := str.Of("pkg/Path/FILE.txt").BeforeLastFold("/path/").String()
println(v)
// #string pkg
Between
Between returns the substring between the first occurrence of start and the last occurrence of end. Returns an empty string if either marker is missing or overlapping.
v := str.Of("This is my name").Between("This", "name").String()
println(v)
// #string is my
BetweenFirst
BetweenFirst returns the substring between the first occurrence of start and the first occurrence of end after it. Returns an empty string if markers are missing.
v := str.Of("[a] bc [d]").BetweenFirst("[", "]").String()
println(v)
// #string a
CharAt
CharAt returns the rune at the given index and true if within bounds.
v, ok := str.Of("gopher").CharAt(2)
println(string(v), ok)
// #string p
// #bool true
CommonPrefix
CommonPrefix 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.
v := str.Of("gopher").CommonPrefix("go", "gold").String()
println(v)
// #string go
CommonSuffix
CommonSuffix 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.
v := str.Of("main_test.go").CommonSuffix("user_test.go", "api_test.go").String()
println(v)
// #string _test.go
Limit
Limit 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...
Slice
Slice returns the substring between rune offsets [start:end). Indices are clamped; if start >= end the result is empty.
v := str.Of("naïve café").Slice(3, 7).String()
println(v)
// #string e ca
SubstrReplace
SubstrReplace 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
Take returns the first length runes of the string (clamped).
v := str.Of("gophers").Take(3).String()
println(v)
// #string gop
TakeLast
TakeLast returns the last length runes of the string (clamped).
v := str.Of("gophers").TakeLast(4).String()
println(v)
// #string hers
Transform
Repeat
Repeat repeats the string count times (non-negative).
v := str.Of("go").Repeat(3).String()
println(v)
// #string gogogo
Reverse
Reverse returns a rune-safe reversed string.
v := str.Of("naïve").Reverse().String()
println(v)
// #string evïan
Transliterate
Transliterate replaces a small set of accented runes with ASCII equivalents.
v := str.Of("café déjà vu").Transliterate().String()
println(v)
// #string cafe deja vu
Words
FirstWord
FirstWord returns the first word token or empty string.
v := str.Of("Hello world")
println(v.FirstWord().String())
// #string Hello
Initials
Initials returns the uppercase first rune of each detected word. Words are split the same way as SplitWords, including camelCase boundaries.
v := str.Of("portableNetwork graphics").Initials().String()
println(v)
// #string PNG
Join
Join joins the provided words with sep.
v := str.Of("unused").Join([]string{"foo", "bar"}, "-").String()
println(v)
// #string foo-bar
LastWord
LastWord returns the last word token or empty string.
v := str.Of("Hello world").LastWord().String()
println(v)
// #string world
SplitWords
SplitWords splits the string into words (Unicode letters/digits runs).
v := str.Of("one, two, three").SplitWords()
println(v)
// #[]string [one two three]
WordCount
WordCount returns the number of word tokens (letters/digits runs).
v := str.Of("Hello, world!").WordCount()
println(v)
// #int 2
Words
Words limits the string to count words, appending suffix if truncated.
v := str.Of("Perfectly balanced, as all things should be.").Words(3, " >>>").String()
println(v)
// #string Perfectly balanced as >>>
WrapWords
WrapWords wraps the string to the given width on word boundaries, using breakStr between lines.
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.