Repository navigation
Releases: goforj/str
Release list
v3.0.0
Version 3 aligns the fluent API with all 56 non-constructor functions in Go 1.27's strings package while keeping Go 1.24 as the minimum and adding no runtime dependencies.
Install
go get github.com/goforj/str/v3@v3.0.0import "github.com/goforj/str/v3"Breaking changes and migration
Changing the import path alone is not enough. Review the v2 to v3 migration guide for the complete behavior changes.
Trimming and joining
| v2 | v3 |
|---|---|
value.Trim() |
value.TrimSpace() |
value.TrimChars(chars) |
value.Trim(chars) |
value.TrimLeft() |
value.TrimLeftFunc(unicode.IsSpace) |
value.TrimRight() |
value.TrimRightFunc(unicode.IsSpace) |
value.Join(elements, sep) |
str.Join(elements, sep) |
Trim, TrimLeft, and TrimRight accept cutsets. An empty cutset leaves the input unchanged. TrimChars and the receiver method Join are removed.
Search indexes and empty matches
Index and LastIndex now return byte offsets. All standard index methods follow that rule; application helpers such as Slice, Take, and CharAt still use rune positions.
// v2: Index("llo") returned 2.
value := str.Of("héllo")
index := value.Index("llo")
fmt.Println(index)
// 3
fmt.Println(value.String()[index:])
// lloEmpty searches follow each standard function's contract. For example, Contains("") is true, Count("") on "abc" is 4, and ReplaceAll("", "-") produces "-a-b-c-".
Folded predicates also match empty searches. Empty-search replacement helpers insert at the corresponding boundaries. Replace, ReplaceAll, ReplaceFold, and each entry in ReplaceArray preserve UTF-8 sequence boundaries; Swap follows strings.Replacer byte boundaries, so an empty key can split a multibyte rune. Swap remains one-pass; ReplaceArray remains sequential.
Lines, casing, and repetition
Lines now returns iter.Seq[string], preserves newline bytes, and omits an extra empty element after a trailing newline.
// v2: Lines() returned ["a" "b" ""].
fmt.Printf("%q\n", slices.Collect(str.Of("a\r\nb\n").Lines()))
// ["a\r\n" "b\n"]Use NormalizeNewlines().Split("\n") for the old normalized slice behavior. Lines, SplitSeq, and SplitAfterSeq are single-use; FieldsSeq and FieldsFuncSeq restart on each iteration.
Title now preserves non-initial letters like strings.Title: "hELLO wORLD" becomes "HELLO WORLD", where v2 produced "Hello World". It carries the standard deprecation notice for Unicode word-boundary limitations. Repeat now panics for negative counts and overflow.
Additional standard operations
The API adds the Cut family, fields and split variants, predicate-based search and trimming, Replace(old, new, n), Map, Clone, ToValidUTF8, special-case conversion, and the remaining standard string functions. See the complete API contract.
The source string becomes the receiver, remaining arguments retain their order, and a single string result becomes str.String. Multiple results, slices, and iterators retain their standard types. Join is a package-level constructor. Stateful strings.Builder, strings.Reader, and strings.Replacer remain in the standard library.
CutLast is backported so it also works on Go 1.24. The docs and examples modules are development tooling; only the root runtime module is released. Existing v2 consumers can continue using the v2 module path.
Full changelog: v2.0.1 to v3.0.0.
v2.0.1
v2.0.0
v2 makes str smaller and more predictable without changing the reason it exists: readable string chains.
The API now has one name for each operation, follows Go's standard library where there is an established name, and handles Unicode consistently. Fluent operations such as Join, ToBase64, and FromBase64 remain part of the library.
Highlights
- Standard library naming such as
Trim,HasPrefix,HasSuffix,EqualFold,TrimPrefix, andTrimSuffix. - No aliases or compatibility shims. Each operation has one supported spelling.
- Rune-aware indexing, slicing, padding, casing, and text limits.
- Better word detection for camel case and acronyms such as
HTTPRequestID. - Clear empty-search behavior and errors for invalid parsing or match patterns.
- Improved
Plural,Singular,Slug,Words, andWrapWordsbehavior for application code. - A generated API reference with examples that are built, run, and checked by the test suite.
Breaking changes
The module path is now:
import "github.com/goforj/str/v2"Aliases and several narrow wrappers were removed, and some methods now use Go-style names or more explicit signatures. See the v1 to v2 migration guide for direct replacements and behavior changes.
Install
go get github.com/goforj/str/v2@v2.0.0v2 requires Go 1.24 or newer and has no third-party dependencies.
Full Changelog: v1.3.0...v2.0.0
v1.3.0
This release expands str with a small set of high-leverage additions:
- Case-insensitive search helpers now include positional and counting APIs.
- New character-class predicates cover common validation checks.
- Word and affix helpers fill a few practical gaps without expanding the surface area.
- Native-type conversions were added in a deliberately minimal form:
Int,Float64, andBool.
str aims to be intentionally simple by providing sane defaults, no aliased helpers and high-value primitives.
Search
IndexFold()
Returns the rune index of the first case-insensitive match.
v := str.Of("Go gopher GO").IndexFold("go")
println(v)
// 0LastIndexFold()
Returns the rune index of the last case-insensitive match.
v := str.Of("Go gopher GO").LastIndexFold("go")
println(v)
// 10CountFold()
Counts non-overlapping case-insensitive matches.
v := str.Of("GoGOgophergo").CountFold("go")
println(v)
// 4Checks
IsAlpha()
Reports whether a string consists only of Unicode letters.
v := str.Of("Gopher").IsAlpha()
println(v)
// trueIsAlnum()
Reports whether a string consists only of Unicode letters or numbers.
v := str.Of("Gopher2025").IsAlnum()
println(v)
// trueIsNumeric()
Reports whether a string consists only of Unicode numbers.
v := str.Of("12345").IsNumeric()
println(v)
// trueWords
Initials()
Extracts the uppercase first rune of each detected word.
v := str.Of("portableNetwork graphics").Initials().String()
println(v)
// PNGSubstrings
BeforeFold()
Returns the substring before the first case-insensitive separator match.
v := str.Of("GoPHER::go").BeforeFold("::GO").String()
println(v)
// GoPHERAfterFold()
Returns the substring after the first case-insensitive separator match.
v := str.Of("gopher::GO-team").AfterFold("::go").String()
println(v)
// -teamBeforeLastFold()
Returns the substring before the last case-insensitive separator match.
v := str.Of("pkg/Path/FILE.txt").BeforeLastFold("/path/").String()
println(v)
// pkgAfterLastFold()
Returns the substring after the last case-insensitive separator match.
v := str.Of("pkg/Path/FILE.txt").AfterLastFold("/path/").String()
println(v)
// FILE.txtCommonPrefix()
Returns the longest shared prefix across the receiver and the provided strings.
v := str.Of("gopher").CommonPrefix("go", "gold").String()
println(v)
// goCommonSuffix()
Returns the longest shared suffix across the receiver and the provided strings.
v := str.Of("main_test.go").CommonSuffix("user_test.go", "api_test.go").String()
println(v)
// _test.goAffixes
HasSurrounding()
Reports whether a string starts and ends with the expected delimiters.
v := str.Of(`"GoForj"`).HasSurrounding(`"`, "")
println(v)
// trueConversion
Int()
Parses the string as a base-10 int using strict strconv.Atoi semantics.
v, err := str.Of("42").Int()
println(v, err == nil)
// 42 trueFloat64()
Parses the string as a float64 using strict strconv.ParseFloat semantics.
v, err := str.Of("3.14").Float64()
println(v, err == nil)
// 3.14 trueBool()
Parses the string as a bool using strict strconv.ParseBool semantics.
v, err := str.Of("true").Bool()
println(v, err == nil)
// true trueFull Changelog: v1.2.0...v1.3.0
v1.2.0
Changes
- feat: add TrimSpace as wrapper to Trim("") @cmilesdev
- test: align test filenames with source files @cmilesdev
Full Changelog: v1.1.2...v1.2.0
v1.1.2
v1.1.1
v1.1.0
v1.0.0
Full Changelog: https://github.com/goforj/str/commits/v1.0.0