Documentation
¶
Overview ¶
Package str is a pipeline-first string toolkit for Go.
Every transformation function has the signature func(string) string, making them composable with Pipe. Functions that need configuration use partial application to return func(string) string.
All length, width, and index parameters count runes, not bytes. All functions are safe for concurrent use. No function panics for any input.
Compose ¶
Pipe and PipeErr compose multiple transformations into a single function.
Transform ¶
Case conversion, reversal, whitespace normalization, and slug generation.
Format ¶
Padding, truncation, substring extraction, and word wrapping.
Measure ¶
String distance and similarity algorithms.
Index ¶
- func CollapseWhitespace(s string) string
- func JaroWinkler(a, b string) float64
- func Levenshtein(a, b string) int
- func Lines(s string) []string
- func NaturalSortKey(s string) string
- func PadLeft(padStr string, width int) func(string) string
- func PadRight(padStr string, width int) func(string) string
- func Pipe(fns ...func(string) string) func(string) string
- func PipeErr(fns ...func(string) (string, error)) func(string) (string, error)
- func PipeIf(predicate func(string) bool, fn func(string) string) func(string) string
- func PipeMap(split func(string) []string, join string, fn func(string) string) func(string) string
- func PipeUnless(predicate func(string) bool, fn func(string) string) func(string) string
- func Pluralize(count int, plural string) func(string) string
- func RandomToken(opts ...TokenOption) string
- func Reverse(s string) string
- func SlugifyASCII(s string) string
- func Substring(start, length int) func(string) string
- func ToCamelCase(s string) string
- func ToCamelCaseWith(opts ...CaseOption) func(string) string
- func ToKebabCase(s string) string
- func ToKebabCaseWith(opts ...CaseOption) func(string) string
- func ToPascalCase(s string) string
- func ToPascalCaseWith(opts ...CaseOption) func(string) string
- func ToScreamingSnake(s string) string
- func ToScreamingSnakeWith(opts ...CaseOption) func(string) string
- func ToSnakeCase(s string) string
- func ToSnakeCaseWith(opts ...CaseOption) func(string) string
- func ToTitleCase(s string) string
- func ToTitleCaseEnglish(s string) string
- func ToTitleCaseWith(opts ...CaseOption) func(string) string
- func TrimSpace(s string) string
- func Truncate(maxLen int, ellipsis string) func(string) string
- func Words(s string) []string
- func Wrap(width int, opts ...WrapOption) func(string) string
- type CaseOption
- type Match
- type TokenOption
- type WrapOption
Examples ¶
- CollapseWhitespace
- FuzzyMatch
- JaroWinkler
- Levenshtein
- NaturalSortKey
- PadLeft
- PadLeft (Pipe)
- PadRight
- Pipe
- PipeErr
- PipeIf
- PipeMap
- PipeMap (Words)
- PipeUnless
- Pluralize
- RandomToken
- RandomToken (Options)
- Reverse
- Reverse (Pipe)
- SlugifyASCII
- SlugifyASCII (Pipe)
- Substring
- ToCamelCase
- ToKebabCase
- ToPascalCase
- ToScreamingSnake
- ToSnakeCase
- ToSnakeCase (Pipe)
- ToSnakeCaseWith
- ToTitleCase
- ToTitleCaseEnglish
- TrimSpace
- Truncate
- Truncate (Pipe)
- Wrap
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CollapseWhitespace ¶
CollapseWhitespace collapses all runs of Unicode whitespace (spaces, tabs, newlines, vertical tabs, etc.) to a single ASCII space. Uses unicode.IsSpace for classification. Leading and trailing whitespace is also collapsed to a single space if present, then trimmed.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.CollapseWhitespace("hello \t\n world"))
}
Output: hello world
func JaroWinkler ¶
JaroWinkler returns the Jaro-Winkler similarity between two strings. Returns a value between 0.0 (completely different) and 1.0 (identical). Uses the standard Winkler prefix bonus scaling factor p=0.1 with max prefix length 4.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Printf("%.2f\n", str.JaroWinkler("hello", "hello"))
}
Output: 1.00
func Levenshtein ¶
Levenshtein returns the edit distance between two strings. Uses a 2-row rolling array for O(min(m,n)) space complexity.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.Levenshtein("kitten", "sitting"))
}
Output: 3
func Lines ¶
Lines splits a string on newlines. Empty string returns []string{""}. Splits on "\n" only; "\r" is preserved if present.
func NaturalSortKey ¶
NaturalSortKey returns a string key that sorts naturally when compared lexicographically. Numeric segments (ASCII digits) are zero-padded to 20 digits. Case is folded to lowercase. "file2" sorts before "file10".
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.NaturalSortKey("file2"))
}
Output: file00000000000000000002
func PadLeft ¶
PadLeft returns a function that pads the input string on the left with the given pad string until it reaches the specified width (in runes). Multi-character pad strings are truncated on the final repetition to hit exactly width. Empty pad string or width <= input length returns input unchanged.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.PadLeft("0", 8)("1234"))
}
Output: 00001234
Example (Pipe) ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
format := str.Pipe(str.TrimSpace, str.PadLeft("0", 8))
fmt.Println(format(" 42 "))
}
Output: 00000042
func PadRight ¶
PadRight returns a function that pads the input string on the right with the given pad string until it reaches the specified width (in runes).
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.PadRight(".", 10)("hello"))
}
Output: hello.....
func Pipe ¶
Pipe composes multiple string transformers into a single function. Functions are applied left to right. With zero functions, Pipe returns an identity function that returns the input unchanged.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
normalize := str.Pipe(
str.TrimSpace,
str.CollapseWhitespace,
str.ToSnakeCase,
)
fmt.Println(normalize(" HelloWorld "))
}
Output: hello_world
func PipeErr ¶
PipeErr composes multiple fallible string transformers into a single function. Functions are applied left to right. Short-circuits on the first non-nil error; the error is returned unwrapped from the failing function. With zero functions, PipeErr returns an identity function that returns the input and nil.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
upper := func(s string) (string, error) { return str.Reverse(s), nil }
fn := str.PipeErr(upper)
result, _ := fn("hello")
fmt.Println(result)
}
Output: olleh
func PipeIf ¶
PipeIf returns a transformer that applies fn only when the predicate returns true. If the predicate returns false, the input passes through unchanged. Nil predicate is treated as always-false (no-op). Nil fn is a no-op.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
isLong := func(s string) bool { return len([]rune(s)) > 10 }
shorten := str.Pipe(
str.TrimSpace,
str.PipeIf(isLong, str.Truncate(10, "...")),
)
fmt.Println(shorten(" hello "))
fmt.Println(shorten(" this is a long string "))
}
Output: hello this is...
func PipeMap ¶
PipeMap returns a transformer that splits the input using split, applies fn to each part, and rejoins with the join string. Nil split or nil fn returns the input unchanged.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
trimLines := str.PipeMap(str.Lines, "\n", str.TrimSpace)
fmt.Println(trimLines(" hello \n world "))
}
Output: hello world
Example (Words) ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
shoutWords := str.PipeMap(str.Words, " ", str.ToScreamingSnake)
fmt.Println(shoutWords("hello world"))
}
Output: HELLO WORLD
func PipeUnless ¶
PipeUnless returns a transformer that applies fn only when the predicate returns false. If the predicate returns true, the input passes through unchanged. Nil predicate is treated as always-false, so fn always applies. Nil fn is a no-op.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
isEmpty := func(s string) bool { return s == "" }
fn := str.PipeUnless(isEmpty, str.SlugifyASCII)
fmt.Println(fn("Hello World"))
fmt.Println(fn(""))
}
Output: hello-world
func Pluralize ¶
Pluralize returns a transformer that selects between the input (singular) and the given plural form based on count. Returns singular when count == 1, plural otherwise (including count == 0).
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.Pluralize(1, "items")("item"))
fmt.Println(str.Pluralize(5, "items")("item"))
}
Output: item items
func RandomToken ¶
func RandomToken(opts ...TokenOption) string
RandomToken generates a cryptographically random string. Uses crypto/rand for secure randomness. Panics if the OS entropy source fails.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
tok := str.RandomToken()
fmt.Println(len(tok)) // always 20
}
Output: 20
Example (Options) ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
tok := str.RandomToken(str.WithPrefix("tok_"), str.WithLength(6), str.WithCharset("0123456789"))
fmt.Println(len(tok)) // "tok_" (4) + 6 digits
}
Output: 10
func Reverse ¶
Reverse returns the input string with runes in reverse order. This is rune-aware but not grapheme-cluster-aware; combining characters may reorder.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.Reverse("hello"))
}
Output: olleh
Example (Pipe) ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
rev := str.Pipe(str.TrimSpace, str.Reverse)
fmt.Println(rev(" hello "))
}
Output: olleh
func SlugifyASCII ¶
SlugifyASCII generates a URL-safe ASCII slug from the input string. Lowercases, replaces spaces and punctuation with hyphens, collapses consecutive hyphens, and strips all non-ASCII characters.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.SlugifyASCII("Hello, World!"))
}
Output: hello-world
Example (Pipe) ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
slugify := str.Pipe(str.TrimSpace, str.CollapseWhitespace, str.SlugifyASCII)
fmt.Println(slugify(" Hello, World! "))
}
Output: hello-world
func Substring ¶
Substring returns a function that extracts a substring from the input. Start and length are in runes. Negative start counts from the end (Python-style). Negative length returns empty string. Out-of-bounds indices clamp to string boundaries.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.Substring(0, 3)("hello"))
fmt.Println(str.Substring(-3, 2)("abcde"))
}
Output: hel cd
func ToCamelCase ¶
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.ToCamelCase("hello_world"))
fmt.Println(str.ToCamelCase("HTMLParser"))
}
Output: helloWorld htmlParser
func ToCamelCaseWith ¶
func ToCamelCaseWith(opts ...CaseOption) func(string) string
ToCamelCaseWith returns a camelCase transformer using custom options.
func ToKebabCase ¶
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.ToKebabCase("HelloWorld"))
}
Output: hello-world
func ToKebabCaseWith ¶
func ToKebabCaseWith(opts ...CaseOption) func(string) string
ToKebabCaseWith returns a kebab-case transformer using custom options.
func ToPascalCase ¶
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.ToPascalCase("hello_world"))
}
Output: HelloWorld
func ToPascalCaseWith ¶
func ToPascalCaseWith(opts ...CaseOption) func(string) string
ToPascalCaseWith returns a PascalCase transformer using custom options.
func ToScreamingSnake ¶
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.ToScreamingSnake("helloWorld"))
}
Output: HELLO_WORLD
func ToScreamingSnakeWith ¶
func ToScreamingSnakeWith(opts ...CaseOption) func(string) string
ToScreamingSnakeWith returns a SCREAMING_SNAKE transformer using custom options.
func ToSnakeCase ¶
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.ToSnakeCase("HTMLParser"))
fmt.Println(str.ToSnakeCase("getHTTPSURL"))
fmt.Println(str.ToSnakeCase("UserID"))
}
Output: html_parser get_https_url user_id
Example (Pipe) ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
slugify := str.Pipe(str.TrimSpace, str.ToSnakeCase)
fmt.Println(slugify(" Hello World "))
}
Output: hello_world
func ToSnakeCaseWith ¶
func ToSnakeCaseWith(opts ...CaseOption) func(string) string
ToSnakeCaseWith returns a snake_case transformer using custom options.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fn := str.ToSnakeCaseWith(str.WithAcronyms("DAO", "NFT"))
fmt.Println(fn("DAOVoting"))
fmt.Println(fn("NFTMarket"))
}
Output: dao_voting nft_market
func ToTitleCase ¶
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.ToTitleCase("hello_world"))
}
Output: Hello World
func ToTitleCaseEnglish ¶
ToTitleCaseEnglish returns English-aware title case. Capitalizes all words except short function words (articles, conjunctions, prepositions) when they appear mid-sentence. First and last word are always capitalized.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.ToTitleCaseEnglish("a tale of two cities"))
fmt.Println(str.ToTitleCaseEnglish("back_to_the_future"))
}
Output: A Tale of Two Cities Back to the Future
func ToTitleCaseWith ¶
func ToTitleCaseWith(opts ...CaseOption) func(string) string
ToTitleCaseWith returns a Title Case transformer using custom options.
func TrimSpace ¶
TrimSpace removes leading and trailing whitespace from the input string. This is a re-export of strings.TrimSpace for pipeline convenience.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.TrimSpace(" hello "))
}
Output: hello
func Truncate ¶
Truncate returns a function that truncates the input string to maxLen runes. If the input is longer than maxLen, it is truncated and the ellipsis is appended. maxLen includes the ellipsis length. Counts runes, not bytes.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.Truncate(8, "...")("hello world"))
}
Output: hello...
Example (Pipe) ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
shorten := str.Pipe(str.TrimSpace, str.Truncate(10, "..."))
fmt.Println(shorten(" a]very long string "))
}
Output: a]very ...
func Words ¶
Words splits a string on whitespace, matching strings.Fields behavior. Empty string returns nil.
func Wrap ¶
func Wrap(width int, opts ...WrapOption) func(string) string
Wrap returns a function that wraps text at the specified width (in runes). Default behavior is WrapBeforeWord with "\n" line breaks. Width of 0 returns input unchanged.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
fmt.Println(str.Wrap(10, str.WrapHardBreak)("abcdefghijklmno"))
}
Output: abcdefghij klmno
Types ¶
type CaseOption ¶
type CaseOption func(*caseConfig)
CaseOption configures case conversion behavior.
func WithAcronyms ¶
func WithAcronyms(words ...string) CaseOption
WithAcronyms replaces the default acronym list entirely. Users who want defaults plus custom acronyms must include both.
type Match ¶
type Match struct {
Score float64 // 0.0 to 1.0 (JaroWinkler similarity)
Index int // position in the haystack
Value string // the matched string
}
Match represents a fuzzy match result.
func FuzzyMatch ¶
FuzzyMatch scores each haystack entry against the needle using JaroWinkler. Returns entries with Score >= 0.7, sorted by Score descending. Comparison is case-insensitive. Empty needle or haystack returns nil.
Example ¶
package main
import (
"fmt"
"github.com/schigh/str"
)
func main() {
hay := []string{"hello", "help", "world"}
matches := str.FuzzyMatch("helo", hay)
if len(matches) > 0 {
fmt.Println(matches[0].Value)
}
}
Output: hello
func FuzzyMatchAll ¶
FuzzyMatchAll is like FuzzyMatch but returns all entries with Score > 0.
type TokenOption ¶
type TokenOption func(*tokenConfig)
TokenOption configures RandomToken behavior.
func WithCharset ¶
func WithCharset(cs string) TokenOption
WithCharset sets the character set to sample from (default alphanumeric). Duplicate characters are deduplicated.
func WithLength ¶
func WithLength(n int) TokenOption
WithLength sets the number of random characters (default 20). Prefix is not included in this count.
func WithPrefix ¶
func WithPrefix(p string) TokenOption
WithPrefix sets a prefix prepended to the random characters.
type WrapOption ¶
type WrapOption func(*wrapConfig)
WrapOption configures the behavior of Wrap.
var WrapAfterWord WrapOption = func(c *wrapConfig) { c.behavior = behaviorAfterWord }
WrapAfterWord wraps after the word that extends past the line width.
var WrapBeforeWord WrapOption = func(c *wrapConfig) { c.behavior = behaviorBeforeWord }
WrapBeforeWord wraps before the word that would extend past the line width.
var WrapHardBreak WrapOption = func(c *wrapConfig) { c.behavior = behaviorHardBreak }
WrapHardBreak breaks mid-word at exactly the line width.
func WithIndent ¶
func WithIndent(indent string) WrapOption
WithIndent sets a prefix for continuation lines.
func WithLineBreak ¶
func WithLineBreak(lb string) WrapOption
WithLineBreak sets the line break string (default "\n").