{"id":35132164,"url":"https://github.com/goforj/str","last_synced_at":"2026-04-06T04:31:19.889Z","repository":{"id":329204073,"uuid":"1118484975","full_name":"goforj/str","owner":"goforj","description":"A fluent, Laravel-inspired string toolkit for Go with explicit, rune-safe helpers and predictable behavior.","archived":false,"fork":false,"pushed_at":"2026-03-06T10:39:58.000Z","size":1147,"stargazers_count":154,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-06T14:50:14.862Z","etag":null,"topics":["fluent-api","go","goforj","golang","laravel-inspired","rune-safe","string","string-utils","text-processing","unicode"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goforj.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-17T20:35:15.000Z","updated_at":"2026-03-06T10:40:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/goforj/str","commit_stats":null,"previous_names":["goforj/str"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/goforj/str","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goforj%2Fstr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goforj%2Fstr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goforj%2Fstr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goforj%2Fstr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goforj","download_url":"https://codeload.github.com/goforj/str/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goforj%2Fstr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31459998,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T21:22:52.476Z","status":"online","status_checked_at":"2026-04-06T02:00:07.287Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fluent-api","go","goforj","golang","laravel-inspired","rune-safe","string","string-utils","text-processing","unicode"],"created_at":"2025-12-28T06:32:07.807Z","updated_at":"2026-04-06T04:31:19.883Z","avatar_url":"https://github.com/goforj.png","language":"Go","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./docs/images/logo.png?v=2\" width=\"300\" alt=\"str logo\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    A fluent, Laravel-inspired string toolkit for Go, focused on rune-safe helpers,\n    expressive transformations, and predictable behavior beyond the standard library.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://pkg.go.dev/github.com/goforj/str\"\u003e\u003cimg src=\"https://pkg.go.dev/badge/github.com/goforj/str.svg\" alt=\"Go Reference\"\u003e\u003c/a\u003e\n    \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/goforj/str/actions\"\u003e\u003cimg src=\"https://github.com/goforj/str/actions/workflows/test.yml/badge.svg\" alt=\"Go Test\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://golang.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/go-1.18+-blue?logo=go\" alt=\"Go version\"\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/tag/goforj/str?label=version\u0026sort=semver\" alt=\"Latest tag\"\u003e\n    \u003ca href=\"https://codecov.io/gh/goforj/str\" \u003e\u003cimg src=\"https://codecov.io/github/goforj/str/graph/badge.svg?token=9KT46ZORP3\"/\u003e\u003c/a\u003e\n\u003c!-- test-count:embed:start --\u003e\n    \u003cimg src=\"https://img.shields.io/badge/tests-230-brightgreen\" alt=\"Tests\"\u003e\n\u003c!-- test-count:embed:end --\u003e\n    \u003ca href=\"https://goreportcard.com/report/github.com/goforj/str\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/goforj/str\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Installation\n\n```sh\ngo get github.com/goforj/str\n```\n\n## Runnable examples\n\nEvery function has a corresponding runnable example under [`./examples`](./examples).\n\nThese 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.\n\nAn automated test executes **every example** to verify it builds and runs successfully.\n\nThis guarantees all examples are valid, up-to-date, and remain functional as the API evolves.\n\n\u003c!-- api:embed:start --\u003e\n\n## API Index\n\n| Group | Functions |\n|------:|-----------|\n| **Affixes** | [ChopEnd](#chopend) [ChopStart](#chopstart) [EnsurePrefix](#ensureprefix) [EnsureSuffix](#ensuresuffix) [HasSurrounding](#hassurrounding) [Unwrap](#unwrap) [Wrap](#wrap) |\n| **Case** | [Camel](#camel) [Headline](#headline) [Kebab](#kebab) [LcFirst](#lcfirst) [Pascal](#pascal) [Snake](#snake) [Title](#title) [ToLower](#tolower) [ToTitle](#totitle) [ToUpper](#toupper) [UcFirst](#ucfirst) [UcWords](#ucwords) |\n| **Checks** | [IsASCII](#isascii) [IsAlnum](#isalnum) [IsAlpha](#isalpha) [IsBlank](#isblank) [IsEmpty](#isempty) [IsNumeric](#isnumeric) |\n| **Cleanup** | [Deduplicate](#deduplicate) [NormalizeNewlines](#normalizenewlines) [NormalizeSpace](#normalizespace) [Squish](#squish) [Trim](#trim) [TrimLeft](#trimleft) [TrimRight](#trimright) [TrimSpace](#trimspace) |\n| **Comparison** | [Equals](#equals) [EqualsFold](#equalsfold) |\n| **Compose** | [Append](#append) [NewLine](#newline) [Prepend](#prepend) |\n| **Constructor** | [Of](#of) |\n| **Conversion** | [Bool](#bool) [Float64](#float64) [Int](#int) |\n| **Encoding** | [FromBase64](#frombase64) [ToBase64](#tobase64) |\n| **Fluent** | [GoString](#gostring) [String](#string) |\n| **Length** | [Len](#len) [RuneCount](#runecount) |\n| **Masking** | [Mask](#mask) |\n| **Match** | [Is](#is) [IsMatch](#ismatch) [Match](#match) [MatchAll](#matchall) |\n| **Padding** | [PadBoth](#padboth) [PadLeft](#padleft) [PadRight](#padright) |\n| **Pluralize** | [Plural](#plural) [Singular](#singular) |\n| **Replace** | [Remove](#remove) [ReplaceAll](#replaceall) [ReplaceArray](#replacearray) [ReplaceEnd](#replaceend) [ReplaceFirst](#replacefirst) [ReplaceFirstFold](#replacefirstfold) [ReplaceFold](#replacefold) [ReplaceLast](#replacelast) [ReplaceLastFold](#replacelastfold) [ReplaceMatches](#replacematches) [ReplaceStart](#replacestart) [Swap](#swap) |\n| **Search** | [Contains](#contains) [ContainsAll](#containsall) [ContainsAllFold](#containsallfold) [ContainsFold](#containsfold) [Count](#count) [CountFold](#countfold) [EndsWith](#endswith) [EndsWithFold](#endswithfold) [Index](#index) [IndexFold](#indexfold) [LastIndex](#lastindex) [LastIndexFold](#lastindexfold) [StartsWith](#startswith) [StartsWithFold](#startswithfold) |\n| **Slug** | [Slug](#slug) |\n| **Snippet** | [Excerpt](#excerpt) |\n| **Split** | [Lines](#lines) [Split](#split) [UcSplit](#ucsplit) |\n| **Substrings** | [After](#after) [AfterFold](#afterfold) [AfterLast](#afterlast) [AfterLastFold](#afterlastfold) [Before](#before) [BeforeFold](#beforefold) [BeforeLast](#beforelast) [BeforeLastFold](#beforelastfold) [Between](#between) [BetweenFirst](#betweenfirst) [CharAt](#charat) [CommonPrefix](#commonprefix) [CommonSuffix](#commonsuffix) [Limit](#limit) [Slice](#slice) [SubstrReplace](#substrreplace) [Take](#take) [TakeLast](#takelast) |\n| **Transform** | [Repeat](#repeat) [Reverse](#reverse) [Transliterate](#transliterate) |\n| **Words** | [FirstWord](#firstword) [Initials](#initials) [Join](#join) [LastWord](#lastword) [SplitWords](#splitwords) [WordCount](#wordcount) [Words](#words) [WrapWords](#wrapwords) |\n\n\n## Affixes\n\n### \u003ca id=\"chopend\"\u003e\u003c/a\u003eChopEnd\n\nChopEnd removes the first matching suffix if present.\n\n```go\nv := str.Of(\"file.txt\").ChopEnd(\".txt\", \".md\").String()\nprintln(v)\n// #string file\n```\n\n### \u003ca id=\"chopstart\"\u003e\u003c/a\u003eChopStart\n\nChopStart removes the first matching prefix if present.\n\n```go\nv := str.Of(\"https://goforj.dev\").ChopStart(\"https://\", \"http://\").String()\nprintln(v)\n// #string goforj.dev\n```\n\n### \u003ca id=\"ensureprefix\"\u003e\u003c/a\u003eEnsurePrefix\n\nEnsurePrefix ensures the string starts with prefix, adding it if missing.\n\n```go\nv := str.Of(\"path/to\").EnsurePrefix(\"/\").String()\nprintln(v)\n// #string /path/to\n```\n\n### \u003ca id=\"ensuresuffix\"\u003e\u003c/a\u003eEnsureSuffix\n\nEnsureSuffix ensures the string ends with suffix, adding it if missing.\n\n```go\nv := str.Of(\"path/to\").EnsureSuffix(\"/\").String()\nprintln(v)\n// #string path/to/\n```\n\n### \u003ca id=\"hassurrounding\"\u003e\u003c/a\u003eHasSurrounding\n\nHasSurrounding reports whether the string starts with before and ends with after.\nIf after is empty, before is used for both sides.\n\n```go\nv := str.Of(`\"GoForj\"`).HasSurrounding(`\"`, \"\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"unwrap\"\u003e\u003c/a\u003eUnwrap\n\nUnwrap removes matching before and after strings if present.\n\n```go\nv := str.Of(`\"GoForj\"`).Unwrap(`\"`, `\"`).String()\nprintln(v)\n// #string GoForj\n```\n\n### \u003ca id=\"wrap\"\u003e\u003c/a\u003eWrap\n\nWrap surrounds the string with before and after (after defaults to before).\n\n```go\nv := str.Of(\"GoForj\").Wrap(`\"`, \"\").String()\nprintln(v)\n// #string \"GoForj\"\n```\n\n## Case\n\n### \u003ca id=\"camel\"\u003e\u003c/a\u003eCamel\n\nCamel converts the string to camelCase.\n\n```go\nv := str.Of(\"foo_bar baz\").Camel().String()\nprintln(v)\n// #string fooBarBaz\n```\n\n### \u003ca id=\"headline\"\u003e\u003c/a\u003eHeadline\n\nHeadline converts the string into a human-friendly headline:\nsplits on case/underscores/dashes/whitespace, title-cases words, and lowercases small words (except the first).\n\n```go\nv := str.Of(\"emailNotification_sent\").Headline().String()\nprintln(v)\n// #string Email Notification Sent\n```\n\n### \u003ca id=\"kebab\"\u003e\u003c/a\u003eKebab\n\nKebab converts the string to kebab-case.\n\n```go\nv := str.Of(\"fooBar baz\").Kebab().String()\nprintln(v)\n// #string foo-bar-baz\n```\n\n### \u003ca id=\"lcfirst\"\u003e\u003c/a\u003eLcFirst\n\nLcFirst returns the string with the first rune lower-cased.\n\n```go\nv := str.Of(\"Gopher\").LcFirst().String()\nfmt.Println(v)\n// #string gopher\n```\n\n### \u003ca id=\"pascal\"\u003e\u003c/a\u003ePascal\n\nPascal converts the string to PascalCase.\n\n```go\nv := str.Of(\"foo_bar baz\").Pascal().String()\nfmt.Println(v)\n// #string FooBarBaz\n```\n\n### \u003ca id=\"snake\"\u003e\u003c/a\u003eSnake\n\nSnake converts the string to snake_case using the provided separator (default \"_\").\n\n```go\nv := str.Of(\"fooBar baz\").Snake(\"_\").String()\nprintln(v)\n// #string foo_bar_baz\n```\n\n### \u003ca id=\"title\"\u003e\u003c/a\u003eTitle\n\nTitle converts the string to title case (first letter of each word upper, rest lower) using Unicode rules.\n\n```go\nv := str.Of(\"a nice title uses the correct case\").Title().String()\nprintln(v)\n// #string A Nice Title Uses The Correct Case\n```\n\n### \u003ca id=\"tolower\"\u003e\u003c/a\u003eToLower\n\nToLower returns a lowercase copy of the string using Unicode rules.\n\n```go\nv := str.Of(\"GoLang\").ToLower().String()\nprintln(v)\n// #string golang\n```\n\n### \u003ca id=\"totitle\"\u003e\u003c/a\u003eToTitle\n\nToTitle returns a title-cased copy where all letters are mapped using Unicode title case.\n\n```go\nv := str.Of(\"ß\").ToTitle().String()\nprintln(v)\n// #string SS\n```\n\n### \u003ca id=\"toupper\"\u003e\u003c/a\u003eToUpper\n\nToUpper returns an uppercase copy of the string using Unicode rules.\n\n```go\nv := str.Of(\"GoLang\").ToUpper().String()\nprintln(v)\n// #string GOLANG\n```\n\n### \u003ca id=\"ucfirst\"\u003e\u003c/a\u003eUcFirst\n\nUcFirst returns the string with the first rune upper-cased.\n\n```go\nv := str.Of(\"gopher\").UcFirst().String()\nprintln(v)\n// #string Gopher\n```\n\n### \u003ca id=\"ucwords\"\u003e\u003c/a\u003eUcWords\n\nUcWords uppercases the first rune of each word, leaving the rest unchanged.\nWords are sequences of letters/digits.\n\n```go\nv := str.Of(\"hello WORLD\").UcWords().String()\nprintln(v)\n// #string Hello WORLD\n```\n\n## Checks\n\n### \u003ca id=\"isascii\"\u003e\u003c/a\u003eIsASCII\n\nIsASCII reports whether the string consists solely of 7-bit ASCII runes.\n\n```go\nv := str.Of(\"gopher\").IsASCII()\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"isalnum\"\u003e\u003c/a\u003eIsAlnum\n\nIsAlnum reports whether the string contains at least one rune and every rune is a Unicode letter or number.\n\n```go\nv := str.Of(\"Gopher2025\").IsAlnum()\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"isalpha\"\u003e\u003c/a\u003eIsAlpha\n\nIsAlpha reports whether the string contains at least one rune and every rune is a Unicode letter.\n\n```go\nv := str.Of(\"Gopher\").IsAlpha()\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"isblank\"\u003e\u003c/a\u003eIsBlank\n\nIsBlank reports whether the string contains only Unicode whitespace.\n\n```go\nv := str.Of(\"  \\\\t\\\\n\")\nprintln(v.IsBlank())\n// #bool true\n```\n\n### \u003ca id=\"isempty\"\u003e\u003c/a\u003eIsEmpty\n\nIsEmpty reports whether the string has zero length.\n\n```go\nv := str.Of(\"\").IsEmpty()\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"isnumeric\"\u003e\u003c/a\u003eIsNumeric\n\nIsNumeric reports whether the string contains at least one rune and every rune is a Unicode number.\n\n```go\nv := str.Of(\"12345\").IsNumeric()\nprintln(v)\n// #bool true\n```\n\n## Cleanup\n\n### \u003ca id=\"deduplicate\"\u003e\u003c/a\u003eDeduplicate\n\nDeduplicate collapses consecutive instances of char into a single instance.\nIf char is zero, space is used.\n\n```go\nv := str.Of(\"The   Go   Playground\").Deduplicate(' ').String()\nprintln(v)\n// #string The Go Playground\n```\n\n### \u003ca id=\"normalizenewlines\"\u003e\u003c/a\u003eNormalizeNewlines\n\nNormalizeNewlines replaces CRLF, CR, and Unicode separators with \\n.\n\n```go\nv := str.Of(\"a\\\\r\\\\nb\\\\u2028c\").NormalizeNewlines().String()\nprintln(v)\n// #string a\\nb\\nc\n```\n\n### \u003ca id=\"normalizespace\"\u003e\u003c/a\u003eNormalizeSpace\n\nNormalizeSpace collapses whitespace runs to single spaces without trimming ends.\n\n```go\nv := str.Of(\"  go   forj  \").NormalizeSpace().String()\nprintln(v)\n// #string  go forj\n```\n\n### \u003ca id=\"squish\"\u003e\u003c/a\u003eSquish\n\nSquish trims leading/trailing whitespace and collapses internal whitespace to single spaces.\n\n```go\nv := str.Of(\"   go   forj  \").Squish().String()\nprintln(v)\n// #string go forj\n```\n\n### \u003ca id=\"trim\"\u003e\u003c/a\u003eTrim\n\nTrim trims leading and trailing characters. If cutset is the zero value (empty string), trims Unicode whitespace.\n\n```go\nv := str.Of(\"  GoForj  \").Trim(\"\").String()\nprintln(v)\n// #string GoForj\n```\n\n### \u003ca id=\"trimleft\"\u003e\u003c/a\u003eTrimLeft\n\nTrimLeft trims leading characters. If cutset is the zero value (empty string), trims Unicode whitespace.\n\n```go\nv := str.Of(\"  GoForj  \").TrimLeft(\"\").String()\nprintln(v)\n// #string GoForj\n```\n\n### \u003ca id=\"trimright\"\u003e\u003c/a\u003eTrimRight\n\nTrimRight trims trailing characters. If cutset is the zero value (empty string), trims Unicode whitespace.\n\n```go\nv := str.Of(\"  GoForj  \").TrimRight(\"\").String()\nprintln(v)\n// #string   GoForj\n```\n\n### \u003ca id=\"trimspace\"\u003e\u003c/a\u003eTrimSpace\n\nTrimSpace trims leading and trailing Unicode whitespace.\n\n```go\nv := str.Of(\"  GoForj  \").TrimSpace().String()\nprintln(v)\n// #string GoForj\n```\n\n## Comparison\n\n### \u003ca id=\"equals\"\u003e\u003c/a\u003eEquals\n\nEquals reports whether the string exactly matches other (case-sensitive).\n\n```go\nv := str.Of(\"gopher\").Equals(\"gopher\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"equalsfold\"\u003e\u003c/a\u003eEqualsFold\n\nEqualsFold reports whether the string matches other using Unicode case folding.\n\n```go\nv := str.Of(\"gopher\").EqualsFold(\"GOPHER\")\nprintln(v)\n// #bool true\n```\n\n## Compose\n\n### \u003ca id=\"append\"\u003e\u003c/a\u003eAppend\n\nAppend concatenates the provided parts to the end of the string.\n\n```go\nv := str.Of(\"Go\").Append(\"Forj\", \"!\").String()\nprintln(v)\n// #string GoForj!\n```\n\n### \u003ca id=\"newline\"\u003e\u003c/a\u003eNewLine\n\nNewLine appends a newline character to the string.\n\n```go\nv := str.Of(\"hello\").NewLine().Append(\"world\").String()\nprintln(v)\n// #string hello\\nworld\n```\n\n### \u003ca id=\"prepend\"\u003e\u003c/a\u003ePrepend\n\nPrepend concatenates the provided parts to the beginning of the string.\n\n```go\nv := str.Of(\"World\").Prepend(\"Hello \", \"Go \").String()\nprintln(v)\n// #string Hello Go World\n```\n\n## Constructor\n\n### \u003ca id=\"of\"\u003e\u003c/a\u003eOf\n\nOf wraps a raw string with fluent helpers.\n\n```go\nv := str.Of(\"gopher\")\nprintln(v.String())\n// #string gopher\n```\n\n## Conversion\n\n### \u003ca id=\"bool\"\u003e\u003c/a\u003eBool\n\nBool parses the string as a bool using strconv.ParseBool semantics.\n\n```go\nv, err := str.Of(\"true\").Bool()\nprintln(v, err == nil)\n// #bool true\n// #bool true\n```\n\n### \u003ca id=\"float64\"\u003e\u003c/a\u003eFloat64\n\nFloat64 parses the string as a float64 using strconv.ParseFloat semantics.\n\n```go\nv, err := str.Of(\"3.14\").Float64()\nprintln(v, err == nil)\n// #float64 3.14\n// #bool true\n```\n\n### \u003ca id=\"int\"\u003e\u003c/a\u003eInt\n\nInt parses the string as a base-10 int using strconv.Atoi semantics.\n\n```go\nv, err := str.Of(\"42\").Int()\nprintln(v, err == nil)\n// #int 42\n// #bool true\n```\n\n## Encoding\n\n### \u003ca id=\"frombase64\"\u003e\u003c/a\u003eFromBase64\n\nFromBase64 decodes a standard Base64 string.\n\n```go\nv, err := str.Of(\"Z29waGVy\").FromBase64()\nprintln(v.String(), err)\n// #string gopher\n// #error \u003cnil\u003e\n```\n\n### \u003ca id=\"tobase64\"\u003e\u003c/a\u003eToBase64\n\nToBase64 encodes the string using standard Base64.\n\n```go\nv := str.Of(\"gopher\").ToBase64().String()\nprintln(v)\n// #string Z29waGVy\n```\n\n## Fluent\n\n### \u003ca id=\"gostring\"\u003e\u003c/a\u003eGoString\n\nGoString allows %#v formatting to print the raw string.\n\n```go\nv := str.Of(\"go\")\nprintln(fmt.Sprintf(\"%#v\", v))\n// #string go\n```\n\n### \u003ca id=\"string\"\u003e\u003c/a\u003eString\n\nString returns the underlying raw string value.\n\n```go\nv := str.Of(\"go\").String()\nprintln(v)\n// #string go\n```\n\n## Length\n\n### \u003ca id=\"len\"\u003e\u003c/a\u003eLen\n\nLen returns the number of runes in the string.\n\n```go\nv := str.Of(\"gophers 🦫\").Len()\nprintln(v)\n// #int 9\n```\n\n### \u003ca id=\"runecount\"\u003e\u003c/a\u003eRuneCount\n\nRuneCount is an alias for Len to make intent explicit in mixed codebases.\n\n```go\nv := str.Of(\"naïve\").RuneCount()\nprintln(v)\n// #int 5\n```\n\n## Masking\n\n### \u003ca id=\"mask\"\u003e\u003c/a\u003eMask\n\nMask replaces the middle of the string with the given rune, revealing revealLeft runes\nat the start and revealRight runes at the end. Negative reveal values count from the end.\nIf the reveal counts cover the whole string, the original string is returned.\n\n```go\nv := str.Of(\"gopher@example.com\").Mask('*', 3, 4).String()\nprintln(v)\n// #string gop***********.com\n```\n\n## Match\n\n### \u003ca id=\"is\"\u003e\u003c/a\u003eIs\n\nIs reports whether the string matches any of the provided wildcard patterns.\nPatterns use '*' as a wildcard. Case-sensitive.\n\n```go\nv := str.Of(\"foo/bar\").Is(\"foo/*\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"ismatch\"\u003e\u003c/a\u003eIsMatch\n\nIsMatch reports whether the string matches the provided regular expression.\n\n```go\nv := str.Of(\"abc123\").IsMatch(regexp.MustCompile(`\\d+`))\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"match\"\u003e\u003c/a\u003eMatch\n\nMatch returns the first match and submatches for the pattern.\n\n```go\nre := regexp.MustCompile(`g(o+)`)\nv := str.Of(\"gooo\").Match(re)\nprintln(v)\n// #[]string [gooo ooo]\n```\n\n### \u003ca id=\"matchall\"\u003e\u003c/a\u003eMatchAll\n\nMatchAll returns all matches and submatches for the pattern.\n\n```go\nre := regexp.MustCompile(`go+`)\nv := str.Of(\"go gopher gooo\").MatchAll(re)\nprintln(v)\n// #[][]string [[go] [gooo]]\n```\n\n## Padding\n\n### \u003ca id=\"padboth\"\u003e\u003c/a\u003ePadBoth\n\nPadBoth pads the string on both sides to reach length runes using pad (defaults to space).\n\n```go\nv := str.Of(\"go\").PadBoth(6, \"-\").String()\nprintln(v)\n// #string --go--\n```\n\n### \u003ca id=\"padleft\"\u003e\u003c/a\u003ePadLeft\n\nPadLeft pads the string on the left to reach length runes using pad (defaults to space).\n\n```go\nv := str.Of(\"go\").PadLeft(5, \" \").String()\nprintln(v)\n// #string \\u00a0\\u00a0\\u00a0go\n```\n\n### \u003ca id=\"padright\"\u003e\u003c/a\u003ePadRight\n\nPadRight pads the string on the right to reach length runes using pad (defaults to space).\n\n```go\nv := str.Of(\"go\").PadRight(5, \".\").String()\nprintln(v)\n// #string go...\n```\n\n## Pluralize\n\n### \u003ca id=\"plural\"\u003e\u003c/a\u003ePlural\n\nPlural returns a best-effort English plural form of the last word.\n\n```go\nv := str.Of(\"city\").Plural().String()\nprintln(v)\n// #string cities\n```\n\n### \u003ca id=\"singular\"\u003e\u003c/a\u003eSingular\n\nSingular returns a best-effort English singular form of the last word.\n\n```go\nv := str.Of(\"people\").Singular().String()\nprintln(v)\n// #string person\n```\n\n## Replace\n\n### \u003ca id=\"remove\"\u003e\u003c/a\u003eRemove\n\nRemove deletes all occurrences of provided substrings.\n\n```go\nv := str.Of(\"The Go Toolkit\").Remove(\"Go \").String()\nprintln(v)\n// #string The Toolkit\n```\n\n### \u003ca id=\"replaceall\"\u003e\u003c/a\u003eReplaceAll\n\nReplaceAll replaces all occurrences of old with new in the string.\nIf old is empty, the original string is returned unchanged.\n\n```go\nv := str.Of(\"go gopher go\").ReplaceAll(\"go\", \"Go\").String()\nprintln(v)\n// #string Go Gopher Go\n```\n\n### \u003ca id=\"replacearray\"\u003e\u003c/a\u003eReplaceArray\n\nReplaceArray replaces all occurrences of each old in olds with repl.\n\n```go\nv := str.Of(\"The---Go---Toolkit\")\nprintln(v.ReplaceArray([]string{\"---\"}, \"-\").String())\n// #string The-Go-Toolkit\n```\n\n### \u003ca id=\"replaceend\"\u003e\u003c/a\u003eReplaceEnd\n\nReplaceEnd replaces old with repl at the end of the string, if present.\n\n```go\nv := str.Of(\"file.old\").ReplaceEnd(\".old\", \".new\").String()\nprintln(v)\n// #string file.new\n```\n\n### \u003ca id=\"replacefirst\"\u003e\u003c/a\u003eReplaceFirst\n\nReplaceFirst replaces the first occurrence of old with repl.\n\n```go\nv := str.Of(\"gopher gopher\").ReplaceFirst(\"gopher\", \"go\").String()\nprintln(v)\n// #string go gopher\n```\n\n### \u003ca id=\"replacefirstfold\"\u003e\u003c/a\u003eReplaceFirstFold\n\nReplaceFirstFold replaces the first occurrence of old with repl using Unicode case folding.\n\n```go\nv := str.Of(\"go gopher GO\").ReplaceFirstFold(\"GO\", \"Go\").String()\nprintln(v)\n// #string Go gopher GO\n```\n\n### \u003ca id=\"replacefold\"\u003e\u003c/a\u003eReplaceFold\n\nReplaceFold replaces all occurrences of old with repl using Unicode case folding.\n\n```go\nv := str.Of(\"go gopher GO\").ReplaceFold(\"GO\", \"Go\").String()\nprintln(v)\n// #string Go Gopher Go\n```\n\n### \u003ca id=\"replacelast\"\u003e\u003c/a\u003eReplaceLast\n\nReplaceLast replaces the last occurrence of old with repl.\n\n```go\nv := str.Of(\"gopher gopher\").ReplaceLast(\"gopher\", \"go\").String()\nprintln(v)\n// #string gopher go\n```\n\n### \u003ca id=\"replacelastfold\"\u003e\u003c/a\u003eReplaceLastFold\n\nReplaceLastFold replaces the last occurrence of old with repl using Unicode case folding.\n\n```go\nv := str.Of(\"go gopher GO\").ReplaceLastFold(\"GO\", \"Go\").String()\nprintln(v)\n// #string go gopher Go\n```\n\n### \u003ca id=\"replacematches\"\u003e\u003c/a\u003eReplaceMatches\n\nReplaceMatches applies repl to each regex match and returns the result.\n\n```go\nre := regexp.MustCompile(`\\d+`)\nv := str.Of(\"Hello 123 World\").ReplaceMatches(re, func(m string) string { return \"[\" + m + \"]\" }).String()\nprintln(v)\n// #string Hello [123] World\n```\n\n### \u003ca id=\"replacestart\"\u003e\u003c/a\u003eReplaceStart\n\nReplaceStart replaces old with repl at the start of the string, if present.\n\n```go\nv := str.Of(\"prefix-value\").ReplaceStart(\"prefix-\", \"new-\").String()\nprintln(v)\n// #string new-value\n```\n\n### \u003ca id=\"swap\"\u003e\u003c/a\u003eSwap\n\nSwap replaces multiple values using strings.Replacer built from a map.\n\n```go\npairs := map[string]string{\"Gophers\": \"GoForj\", \"are\": \"is\", \"great\": \"fantastic\"}\nv := str.Of(\"Gophers are great!\").Swap(pairs).String()\nprintln(v)\n// #string GoForj is fantastic!\n```\n\n## Search\n\n### \u003ca id=\"contains\"\u003e\u003c/a\u003eContains\n\nContains reports whether the string contains any of the provided substrings (case-sensitive).\nEmpty substrings return true to match strings.Contains semantics.\n\n```go\nv := str.Of(\"Go means gophers\").Contains(\"rust\", \"gopher\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"containsall\"\u003e\u003c/a\u003eContainsAll\n\nContainsAll reports whether the string contains all provided substrings (case-sensitive).\nEmpty substrings are ignored.\n\n```go\nv := str.Of(\"Go means gophers\").ContainsAll(\"Go\", \"gopher\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"containsallfold\"\u003e\u003c/a\u003eContainsAllFold\n\nContainsAllFold reports whether the string contains all provided substrings, using Unicode\ncase folding for comparisons.\nEmpty substrings are ignored.\n\n```go\nv := str.Of(\"Go means gophers\").ContainsAllFold(\"go\", \"GOPHER\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"containsfold\"\u003e\u003c/a\u003eContainsFold\n\nContainsFold reports whether the string contains any of the provided substrings, using Unicode\ncase folding for comparisons.\nEmpty substrings return true.\n\n```go\nv := str.Of(\"Go means gophers\").ContainsFold(\"GOPHER\", \"rust\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"count\"\u003e\u003c/a\u003eCount\n\nCount returns the number of non-overlapping occurrences of sub.\n\n```go\nv := str.Of(\"gogophergo\").Count(\"go\")\nprintln(v)\n// #int 3\n```\n\n### \u003ca id=\"countfold\"\u003e\u003c/a\u003eCountFold\n\nCountFold returns the number of non-overlapping occurrences of sub using Unicode-aware\ncase-insensitive comparison.\n\n```go\nv := str.Of(\"GoGOgophergo\").CountFold(\"go\")\nprintln(v)\n// #int 4\n```\n\n### \u003ca id=\"endswith\"\u003e\u003c/a\u003eEndsWith\n\nEndsWith reports whether the string ends with any of the provided suffixes (case-sensitive).\n\n```go\nv := str.Of(\"gopher\").EndsWith(\"her\", \"cat\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"endswithfold\"\u003e\u003c/a\u003eEndsWithFold\n\nEndsWithFold reports whether the string ends with any of the provided suffixes using Unicode case folding.\n\n```go\nv := str.Of(\"gopher\").EndsWithFold(\"HER\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"index\"\u003e\u003c/a\u003eIndex\n\nIndex returns the rune index of the first occurrence of sub, or -1 if not found.\n\n```go\nv := str.Of(\"héllo\").Index(\"llo\")\nprintln(v)\n// #int 2\n```\n\n### \u003ca id=\"indexfold\"\u003e\u003c/a\u003eIndexFold\n\nIndexFold returns the rune index of the first occurrence of sub using Unicode-aware\ncase-insensitive comparison, or -1 if not found.\n\n```go\nv := str.Of(\"Go gopher GO\").IndexFold(\"go\")\nprintln(v)\n// #int 0\n```\n\n### \u003ca id=\"lastindex\"\u003e\u003c/a\u003eLastIndex\n\nLastIndex returns the rune index of the last occurrence of sub, or -1 if not found.\n\n```go\nv := str.Of(\"go gophers go\").LastIndex(\"go\")\nprintln(v)\n// #int 10\n```\n\n### \u003ca id=\"lastindexfold\"\u003e\u003c/a\u003eLastIndexFold\n\nLastIndexFold returns the rune index of the last occurrence of sub using Unicode-aware\ncase-insensitive comparison, or -1 if not found.\n\n```go\nv := str.Of(\"Go gopher GO\").LastIndexFold(\"go\")\nprintln(v)\n// #int 10\n```\n\n### \u003ca id=\"startswith\"\u003e\u003c/a\u003eStartsWith\n\nStartsWith reports whether the string starts with any of the provided prefixes (case-sensitive).\n\n```go\nv := str.Of(\"gopher\").StartsWith(\"go\", \"rust\")\nprintln(v)\n// #bool true\n```\n\n### \u003ca id=\"startswithfold\"\u003e\u003c/a\u003eStartsWithFold\n\nStartsWithFold reports whether the string starts with any of the provided prefixes using Unicode case folding.\n\n```go\nv := str.Of(\"gopher\").StartsWithFold(\"GO\")\nprintln(v)\n// #bool true\n```\n\n## Slug\n\n### \u003ca id=\"slug\"\u003e\u003c/a\u003eSlug\n\nSlug produces an ASCII slug using the provided separator (default \"-\"), stripping accents where possible.\nNot locale-aware; intended for identifiers/URLs.\n\n```go\nv := str.Of(\"Go Forj Toolkit\").Slug(\"-\").String()\nprintln(v)\n// #string go-forj-toolkit\n```\n\n## Snippet\n\n### \u003ca id=\"excerpt\"\u003e\u003c/a\u003eExcerpt\n\nExcerpt returns a snippet around the first occurrence of needle with the given radius.\nIf needle is not found, an empty string is returned. If radius \u003c= 0, a default of 100 is used.\nOmission is used at the start/end when text is trimmed (default \"...\").\n\n```go\nv := str.Of(\"This is my name\").Excerpt(\"my\", 3, \"...\")\nprintln(v.String())\n// #string ...is my na...\n```\n\n## Split\n\n### \u003ca id=\"lines\"\u003e\u003c/a\u003eLines\n\nLines splits the string into lines after normalizing newline variants.\n\n```go\nv := str.Of(\"a\\\\r\\\\nb\\\\nc\").Lines()\nprintln(v)\n// #[]string [a b c]\n```\n\n### \u003ca id=\"split\"\u003e\u003c/a\u003eSplit\n\nSplit splits the string by the given separator.\n\n```go\nv := str.Of(\"a,b,c\").Split(\",\")\nprintln(v)\n// #[]string [a b c]\n```\n\n### \u003ca id=\"ucsplit\"\u003e\u003c/a\u003eUcSplit\n\nUcSplit splits the string on uppercase boundaries and delimiters, returning segments.\n\n```go\nv := str.Of(\"HTTPRequestID\").UcSplit()\nprintln(v)\n// #[]string [HTTP Request ID]\n```\n\n## Substrings\n\n### \u003ca id=\"after\"\u003e\u003c/a\u003eAfter\n\nAfter returns the substring after the first occurrence of sep.\nIf sep is empty or not found, the original string is returned.\n\n```go\nv := str.Of(\"gopher::go\").After(\"::\").String()\nprintln(v)\n// #string go\n```\n\n### \u003ca id=\"afterfold\"\u003e\u003c/a\u003eAfterFold\n\nAfterFold returns the substring after the first occurrence of sep using Unicode-aware\ncase-insensitive comparison. If sep is empty or not found, the original string is returned.\n\n```go\nv := str.Of(\"gopher::GO-team\").AfterFold(\"::go\").String()\nprintln(v)\n// #string -team\n```\n\n### \u003ca id=\"afterlast\"\u003e\u003c/a\u003eAfterLast\n\nAfterLast returns the substring after the last occurrence of sep.\nIf sep is empty or not found, the original string is returned.\n\n```go\nv := str.Of(\"pkg/path/file.txt\").AfterLast(\"/\").String()\nprintln(v)\n// #string file.txt\n```\n\n### \u003ca id=\"afterlastfold\"\u003e\u003c/a\u003eAfterLastFold\n\nAfterLastFold returns the substring after the last occurrence of sep using Unicode-aware\ncase-insensitive comparison. If sep is empty or not found, the original string is returned.\n\n```go\nv := str.Of(\"pkg/Path/FILE.txt\").AfterLastFold(\"/path/\").String()\nprintln(v)\n// #string FILE.txt\n```\n\n### \u003ca id=\"before\"\u003e\u003c/a\u003eBefore\n\nBefore returns the substring before the first occurrence of sep.\nIf sep is empty or not found, the original string is returned.\n\n```go\nv := str.Of(\"gopher::go\").Before(\"::\").String()\nprintln(v)\n// #string gopher\n```\n\n### \u003ca id=\"beforefold\"\u003e\u003c/a\u003eBeforeFold\n\nBeforeFold returns the substring before the first occurrence of sep using Unicode-aware\ncase-insensitive comparison. If sep is empty or not found, the original string is returned.\n\n```go\nv := str.Of(\"GoPHER::go\").BeforeFold(\"::GO\").String()\nprintln(v)\n// #string GoPHER\n```\n\n### \u003ca id=\"beforelast\"\u003e\u003c/a\u003eBeforeLast\n\nBeforeLast returns the substring before the last occurrence of sep.\nIf sep is empty or not found, the original string is returned.\n\n```go\nv := str.Of(\"pkg/path/file.txt\").BeforeLast(\"/\").String()\nprintln(v)\n// #string pkg/path\n```\n\n### \u003ca id=\"beforelastfold\"\u003e\u003c/a\u003eBeforeLastFold\n\nBeforeLastFold returns the substring before the last occurrence of sep using Unicode-aware\ncase-insensitive comparison. If sep is empty or not found, the original string is returned.\n\n```go\nv := str.Of(\"pkg/Path/FILE.txt\").BeforeLastFold(\"/path/\").String()\nprintln(v)\n// #string pkg\n```\n\n### \u003ca id=\"between\"\u003e\u003c/a\u003eBetween\n\nBetween returns the substring between the first occurrence of start and the last occurrence of end.\nReturns an empty string if either marker is missing or overlapping.\n\n```go\nv := str.Of(\"This is my name\").Between(\"This\", \"name\").String()\nprintln(v)\n// #string  is my\n```\n\n### \u003ca id=\"betweenfirst\"\u003e\u003c/a\u003eBetweenFirst\n\nBetweenFirst returns the substring between the first occurrence of start and the first occurrence of end after it.\nReturns an empty string if markers are missing.\n\n```go\nv := str.Of(\"[a] bc [d]\").BetweenFirst(\"[\", \"]\").String()\nprintln(v)\n// #string a\n```\n\n### \u003ca id=\"charat\"\u003e\u003c/a\u003eCharAt\n\nCharAt returns the rune at the given index and true if within bounds.\n\n```go\nv, ok := str.Of(\"gopher\").CharAt(2)\nprintln(string(v), ok)\n// #string p\n// #bool true\n```\n\n### \u003ca id=\"commonprefix\"\u003e\u003c/a\u003eCommonPrefix\n\nCommonPrefix returns the longest shared prefix between the string and all provided others.\nComparison is rune-safe. If no others are provided, the original string is returned.\n\n```go\nv := str.Of(\"gopher\").CommonPrefix(\"go\", \"gold\").String()\nprintln(v)\n// #string go\n```\n\n### \u003ca id=\"commonsuffix\"\u003e\u003c/a\u003eCommonSuffix\n\nCommonSuffix returns the longest shared suffix between the string and all provided others.\nComparison is rune-safe. If no others are provided, the original string is returned.\n\n```go\nv := str.Of(\"main_test.go\").CommonSuffix(\"user_test.go\", \"api_test.go\").String()\nprintln(v)\n// #string _test.go\n```\n\n### \u003ca id=\"limit\"\u003e\u003c/a\u003eLimit\n\nLimit truncates the string to length runes, appending suffix if truncation occurs.\n\n```go\nv := str.Of(\"Perfectly balanced, as all things should be.\").Limit(10, \"...\").String()\nprintln(v)\n// #string Perfectly...\n```\n\n### \u003ca id=\"slice\"\u003e\u003c/a\u003eSlice\n\nSlice returns the substring between rune offsets [start:end).\nIndices are clamped; if start \u003e= end the result is empty.\n\n```go\nv := str.Of(\"naïve café\").Slice(3, 7).String()\nprintln(v)\n// #string e ca\n```\n\n### \u003ca id=\"substrreplace\"\u003e\u003c/a\u003eSubstrReplace\n\nSubstrReplace replaces the rune slice in [start:end) with repl.\n\n```go\nv := str.Of(\"naïve café\").SubstrReplace(\"i\", 2, 3).String()\nprintln(v)\n// #string naive café\n```\n\n### \u003ca id=\"take\"\u003e\u003c/a\u003eTake\n\nTake returns the first length runes of the string (clamped).\n\n```go\nv := str.Of(\"gophers\").Take(3).String()\nprintln(v)\n// #string gop\n```\n\n### \u003ca id=\"takelast\"\u003e\u003c/a\u003eTakeLast\n\nTakeLast returns the last length runes of the string (clamped).\n\n```go\nv := str.Of(\"gophers\").TakeLast(4).String()\nprintln(v)\n// #string hers\n```\n\n## Transform\n\n### \u003ca id=\"repeat\"\u003e\u003c/a\u003eRepeat\n\nRepeat repeats the string count times (non-negative).\n\n```go\nv := str.Of(\"go\").Repeat(3).String()\nprintln(v)\n// #string gogogo\n```\n\n### \u003ca id=\"reverse\"\u003e\u003c/a\u003eReverse\n\nReverse returns a rune-safe reversed string.\n\n```go\nv := str.Of(\"naïve\").Reverse().String()\nprintln(v)\n// #string evïan\n```\n\n### \u003ca id=\"transliterate\"\u003e\u003c/a\u003eTransliterate\n\nTransliterate replaces a small set of accented runes with ASCII equivalents.\n\n```go\nv := str.Of(\"café déjà vu\").Transliterate().String()\nprintln(v)\n// #string cafe deja vu\n```\n\n## Words\n\n### \u003ca id=\"firstword\"\u003e\u003c/a\u003eFirstWord\n\nFirstWord returns the first word token or empty string.\n\n```go\nv := str.Of(\"Hello world\")\nprintln(v.FirstWord().String())\n// #string Hello\n```\n\n### \u003ca id=\"initials\"\u003e\u003c/a\u003eInitials\n\nInitials returns the uppercase first rune of each detected word.\nWords are split the same way as SplitWords, including camelCase boundaries.\n\n```go\nv := str.Of(\"portableNetwork graphics\").Initials().String()\nprintln(v)\n// #string PNG\n```\n\n### \u003ca id=\"join\"\u003e\u003c/a\u003eJoin\n\nJoin joins the provided words with sep.\n\n```go\nv := str.Of(\"unused\").Join([]string{\"foo\", \"bar\"}, \"-\").String()\nprintln(v)\n// #string foo-bar\n```\n\n### \u003ca id=\"lastword\"\u003e\u003c/a\u003eLastWord\n\nLastWord returns the last word token or empty string.\n\n```go\nv := str.Of(\"Hello world\").LastWord().String()\nprintln(v)\n// #string world\n```\n\n### \u003ca id=\"splitwords\"\u003e\u003c/a\u003eSplitWords\n\nSplitWords splits the string into words (Unicode letters/digits runs).\n\n```go\nv := str.Of(\"one, two, three\").SplitWords()\nprintln(v)\n// #[]string [one two three]\n```\n\n### \u003ca id=\"wordcount\"\u003e\u003c/a\u003eWordCount\n\nWordCount returns the number of word tokens (letters/digits runs).\n\n```go\nv := str.Of(\"Hello, world!\").WordCount()\nprintln(v)\n// #int 2\n```\n\n### \u003ca id=\"words\"\u003e\u003c/a\u003eWords\n\nWords limits the string to count words, appending suffix if truncated.\n\n```go\nv := str.Of(\"Perfectly balanced, as all things should be.\").Words(3, \" \u003e\u003e\u003e\").String()\nprintln(v)\n// #string Perfectly balanced as \u003e\u003e\u003e\n```\n\n### \u003ca id=\"wrapwords\"\u003e\u003c/a\u003eWrapWords\n\nWrapWords wraps the string to the given width on word boundaries, using breakStr between lines.\n\n```go\nv := str.Of(\"The quick brown fox jumped over the lazy dog.\").WrapWords(20, \"\\n\").String()\nprintln(v)\n// #string The quick brown fox\\njumped over the lazy\\ndog.\n```\n\u003c!-- api:embed:end --\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoforj%2Fstr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoforj%2Fstr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoforj%2Fstr/lists"}