strings2

package module
v0.0.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: BSD-3-Clause Imports: 5 Imported by: 0

Image README

strings2

CI Status Go Reference

strings2 provides utilities for converting slices of words into various casing conventions. It is intended to supplement Go's standard library strings package with helpers for creating formats such as camelCase, PascalCase, snake_case and kebab-case.

Installation

go get github.com/arran4/strings2

Add the module to your project and import it:

import "github.com/arran4/strings2"

Usage

Words must implement fmt.Stringer. The package defines several helper types which satisfy this interface:

words := []strings2.Word{
    strings2.SingleCaseWord("hello"),
    strings2.SingleCaseWord("world"),
}
Parsing

The library includes a robust parser to convert strings into typed Word objects, distinguishing between acronyms, casing, and delimiters.

// Auto-detect format and parse
words, err := strings2.Parse("helloWorld")
// Result: [SingleCaseWord("hello"), FirstUpperCaseWord("World")]

// Parse specific format
words = strings2.ParseSnakeCase("hello_world")

// Configure parser
words, err = strings2.Parse("N.E.W. World", strings2.ParserSmartAcronyms(true))

// Custom multi-byte delimiters using DelimiterDetector
partitioner := strings2.NewPartitioner(strings2.PartitionerConfig{
	DelimiterDetector: func(subs []strings2.SubPart, index int) int {
		if index+1 < len(subs) && subs[index].Rune() == ':' && subs[index+1].Rune() == ':' {
			return 2 // matched "::"
		}
		return 0
	},
})
words, err = strings2.Parse("foo::bar", partitioner)
Case Conversion Functions
strings2.ToCamelCase(words)  // "helloWorld"
strings2.ToPascalCase(words) // "HelloWorld"
strings2.ToKebabCase(words)  // "hello-world"
strings2.ToSnakeCase(words)  // "hello_world"
Mapping and Transformation

You can provide WordMapper (func([]Word) []Word), PartMapper, or SubPartMapper natively into formatting functions or Parse/StringToWords as variadic options to filter, transform, or reorder elements during parsing and generation.

import "github.com/arran4/strings2/mappers"

// Convert strings natively with inline options
acronym, _ := strings2.ToFormattedString(
    "National Aeronautics and Space Administration",
    strings2.WordMapper(mappers.Acronym),
    strings2.OptionCaseMode(strings2.CMVerbatim),
    strings2.OptionDelimiter(""),
)
// Result: "NAASA"

// Reversing words natively
reversed, _ := strings2.ToCamel("hello world from strings2", strings2.WordMapper(mappers.Reverse))
// Result: "strings2FromWorldHello"

// Filter out numbers natively
filterNumbers := mappers.Filter(func(w strings2.Word) bool {
    return !strings.ContainsAny(w.String(), "0123456789")
})
noDigits, _ := strings2.ToSnake("hello 123 world", strings2.WordMapper(filterNumbers))
// Result: "hello_world"

Multiple mapping functions can be passed simultaneously and will be applied sequentially in their respective lifecycle phase (SubPart, Part, then Word).

Customising Formatting

Behaviour can be tuned with options passed to each function. Some commonly used options include:

  • OptionDelimiter(string) – change the delimiter used between words.
  • OptionCaseMode(CaseMode) – set the case transformation mode. Modes include:
    • CMVerbatim
    • CMFirstTitle
    • CMAllTitle
    • CMFirstLower
    • CMWhispering
    • CMScreaming
  • OptionFirstUpper() – force the result to start with an uppercase letter.
  • OptionFirstLower() – force the result to start with a lowercase letter.

Examples:

// Custom delimiter
fmt.Println(strings2.ToKebabCase(words, strings2.OptionDelimiter("|")))

// Screaming snake case
fmt.Println(strings2.ToSnakeCase(words, strings2.OptionCaseMode(strings2.CMScreaming)))
CLI Mode

The library also provides a command-line interface that exposes all these options, ensuring that the CLI mode has as much flexibility as the code (without being obligated to use smart defaults).

strings2 camel "hello world"
# Result: helloWorld

strings2 snake --screaming "hello world"
# Result: HELLO_WORLD

strings2 kebab --first-upper "hello world"
# Result: Hello-world

You can pipe input into the CLI as well:

echo "hello world" | strings2 pascal
# Result: HelloWorld

Available flags across commands:

  • --delimiter, -d (string): Override the delimiter
  • --screaming, -S: Enforce uppercase formatting
  • --whispering, -w: Enforce lowercase formatting
  • --first-upper, -U: Capitalize the first letter
  • --first-lower, -l: Lowercase the first letter
  • --mix-case-support, -m: Enable splitting of mixed case words
  • --no-smart-acronyms: Disable acronym preservation
  • --number-splitting: Enable letter-digit boundary splitting

Options are composable so multiple behaviours can be applied at once. See the documentation in `types.go` for details on further options.

## TODO

- Support slices for flags when the gosubc version supports it.

## License

This project is licensed under the BSD 3-Clause License - see the [LICENSE](LICENSE) file for details.

Image Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrRune = errors.New("invalid rune")

Functions

func FromCamelToCamel

func FromCamelToCamel(input string, opts ...any) (string, error)

FromCamelToCamel and friends? The user requested permutations.

func FromCamelToDarwin added in v0.0.9

func FromCamelToDarwin(input string, opts ...any) (string, error)

func FromCamelToKebab

func FromCamelToKebab(input string, opts ...any) (string, error)
Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "helloWorld"
	// By default Kebab uses Verbatim casing.
	res, _ := strings2.FromCamelToKebab(input)
	fmt.Println(res)
}
Output:
hello-World

func FromCamelToPascal

func FromCamelToPascal(input string, opts ...any) (string, error)

func FromCamelToSnake

func FromCamelToSnake(input string, opts ...any) (string, error)
Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "helloWorld"
	// By default Snake uses Verbatim casing.
	res, _ := strings2.FromCamelToSnake(input)
	fmt.Println(res)
}
Output:
hello_World

func FromCamelToTitle added in v0.0.10

func FromCamelToTitle(input string, opts ...any) (string, error)

func FromDarwinToCamel added in v0.0.9

func FromDarwinToCamel(input string, opts ...any) (string, error)

func FromDarwinToKebab added in v0.0.9

func FromDarwinToKebab(input string, opts ...any) (string, error)

func FromDarwinToPascal added in v0.0.9

func FromDarwinToPascal(input string, opts ...any) (string, error)

func FromDarwinToSnake added in v0.0.9

func FromDarwinToSnake(input string, opts ...any) (string, error)

func FromDarwinToTitle added in v0.0.10

func FromDarwinToTitle(input string, opts ...any) (string, error)

func FromFormattedString

func FromFormattedString(s string, opts ...any) (string, error)

FromFormattedString is alias for ToFormattedString.

func FromKebabToCamel

func FromKebabToCamel(input string, opts ...any) (string, error)

func FromKebabToDarwin added in v0.0.9

func FromKebabToDarwin(input string, opts ...any) (string, error)

func FromKebabToPascal

func FromKebabToPascal(input string, opts ...any) (string, error)

func FromKebabToSnake

func FromKebabToSnake(input string, opts ...any) (string, error)

func FromKebabToTitle added in v0.0.10

func FromKebabToTitle(input string, opts ...any) (string, error)

func FromPascalToCamel

func FromPascalToCamel(input string, opts ...any) (string, error)

func FromPascalToDarwin added in v0.0.9

func FromPascalToDarwin(input string, opts ...any) (string, error)

func FromPascalToKebab

func FromPascalToKebab(input string, opts ...any) (string, error)

func FromPascalToSnake

func FromPascalToSnake(input string, opts ...any) (string, error)

func FromPascalToTitle added in v0.0.10

func FromPascalToTitle(input string, opts ...any) (string, error)

func FromSnakeToCamel

func FromSnakeToCamel(input string, opts ...any) (string, error)

func FromSnakeToDarwin added in v0.0.9

func FromSnakeToDarwin(input string, opts ...any) (string, error)

func FromSnakeToKebab

func FromSnakeToKebab(input string, opts ...any) (string, error)

func FromSnakeToPascal

func FromSnakeToPascal(input string, opts ...any) (string, error)

func FromSnakeToTitle added in v0.0.10

func FromSnakeToTitle(input string, opts ...any) (string, error)

func FromWordsToCamel

func FromWordsToCamel(words []Word, opts ...Option) (string, error)

FromWordsToCamel converts words to camelCase.

func FromWordsToDarwin added in v0.0.9

func FromWordsToDarwin(words []Word, opts ...Option) (string, error)

func FromWordsToKebab

func FromWordsToKebab(words []Word, opts ...Option) (string, error)

func FromWordsToPascal

func FromWordsToPascal(words []Word, opts ...Option) (string, error)

func FromWordsToSnake

func FromWordsToSnake(words []Word, opts ...Option) (string, error)

func FromWordsToTitle added in v0.0.10

func FromWordsToTitle(words []Word, opts ...Option) (string, error)

func LowerCaseFirst

func LowerCaseFirst(s string) string

LowerCaseFirst lowercases the first character of the string.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "Hello World"
	res := strings2.LowerCaseFirst(input)
	fmt.Println(res)
}
Output:
hello World

func LowerCaseFirstWithErr

func LowerCaseFirstWithErr(s string) (string, error)

LowerCaseFirstWithErr lowercases the first character of the string. It returns an error if the first character is an invalid rune.

func Must

func Must(s string, err error) string

Must swallows error, panics if err != nil

func MustLowerCaseFirst

func MustLowerCaseFirst(s string) string

MustLowerCaseFirst lowercases the first character of the string. It panics if the first character is an invalid rune.

func MustUpperCaseFirst

func MustUpperCaseFirst(s string) string

MustUpperCaseFirst uppercases the first character of the string. It panics if the first character is an invalid rune.

func PartsToFormattedCase

func PartsToFormattedCase(parts []Part, opts ...any) (string, error)

PartsToFormattedCase converts Parts to words then formats them. This is useful when you have intermediate Parts and want to format them directly.

func StringToSubParts

func StringToSubParts(s string) ([]SubPart, Stats)

StringToSubParts converts a string into a slice of SubParts and generates stats.

func ToCamel

func ToCamel(input string, opts ...any) (string, error)

ToCamel converts an input string (auto-detected format) to camelCase.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "hello_world"
	res, _ := strings2.ToCamel(input)
	fmt.Println(res)
}
Output:
helloWorld

func ToCamelCase

func ToCamelCase(words []Word, opts ...Option) (string, error)

ToCamelCase converts words into camelCase format.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	words := []strings2.Word{
		strings2.SingleCaseWord("hello"),
		strings2.SingleCaseWord("world"),
	}
	res, _ := strings2.ToCamelCase(words)
	fmt.Println(res)
}
Output:
helloWorld

func ToDarwin added in v0.0.9

func ToDarwin(input string, opts ...any) (string, error)

ToDarwin converts an input string (auto-detected format) to Darwin_Case.

func ToDarwinCase added in v0.0.9

func ToDarwinCase(words []Word, opts ...Option) (string, error)

ToDarwinCase converts words into Darwin_Case format (Title_Case with underscore).

func ToFormattedCase

func ToFormattedCase(words []Word, opts ...Option) string

ToFormattedCase generates formatted case strings with the given options Deprecated: Use WordsToFormattedCase. This function suppresses errors for backward compatibility.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	words := []strings2.Word{
		strings2.SingleCaseWord("hello"),
		strings2.SingleCaseWord("world"),
	}
	// Screaming snake case
	fmt.Println(strings2.ToFormattedCase(words, strings2.OptionCaseMode(strings2.CMScreaming), strings2.OptionDelimiter("_")))
}
Output:
HELLO_WORLD
Example (CustomSpongeCase)
package main

import (
	"fmt"
	"strings"

	"github.com/arran4/strings2"
)

func main() {
	// Custom formatting: SpongeBob Case (sPoNgEbOb cAsE)
	// This demonstrates iterating over words and applying custom logic.

	input := "hello world"
	words, _ := strings2.Parse(input)

	var sb strings.Builder
	for i, word := range words {
		if i > 0 {
			sb.WriteString(" ")
		}
		s := word.String()
		for j, r := range s {
			// Simple alternating case logic relative to the whole string start or word start
			// Let's do word-local alternating
			if j%2 == 0 {
				sb.WriteString(strings.ToLower(string(r)))
			} else {
				sb.WriteString(strings.ToUpper(string(r)))
			}
		}
	}

	fmt.Println(sb.String())
}
Output:
hElLo wOrLd

func ToFormattedString

func ToFormattedString(s string, opts ...any) (string, error)

ToFormattedString converts string to formatted case (generic entry point).

func ToKebab

func ToKebab(input string, opts ...any) (string, error)

ToKebab converts an input string (auto-detected format) to kebab-case.

func ToKebabCase

func ToKebabCase(words []Word, opts ...Option) (string, error)

ToKebabCase converts words into kebab-case format.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	words := []strings2.Word{
		strings2.SingleCaseWord("hello"),
		strings2.SingleCaseWord("world"),
	}
	res, _ := strings2.ToKebabCase(words)
	fmt.Println(res)
}
Output:
hello-world

func ToPascal

func ToPascal(input string, opts ...any) (string, error)

ToPascal converts an input string (auto-detected format) to PascalCase.

func ToPascalCase

func ToPascalCase(words []Word, opts ...Option) (string, error)

ToPascalCase converts words into PascalCase format.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	words := []strings2.Word{
		strings2.SingleCaseWord("hello"),
		strings2.SingleCaseWord("world"),
	}
	res, _ := strings2.ToPascalCase(words)
	fmt.Println(res)
}
Output:
HelloWorld

func ToSnake

func ToSnake(input string, opts ...any) (string, error)

ToSnake converts an input string (auto-detected format) to snake_case.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "helloWorld"
	// By default Snake uses Verbatim casing, so "World" retains its uppercase 'W'.
	res, _ := strings2.ToSnake(input)
	fmt.Println(res)
}
Output:
hello_World
Example (Options)
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	// Converting Camel to Screaming Snake
	// ToSnake forces delimiter to "_". CMScreaming forces upper.
	input := "camelCase"
	output, _ := strings2.ToSnake(input, strings2.OptionCaseMode(strings2.CMScreaming))
	fmt.Println(output)
}
Output:
CAMEL_CASE

func ToSnakeCase

func ToSnakeCase(words []Word, opts ...Option) (string, error)

ToSnakeCase converts words into snake_case format.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	words := []strings2.Word{
		strings2.SingleCaseWord("hello"),
		strings2.SingleCaseWord("world"),
	}
	res, _ := strings2.ToSnakeCase(words)
	fmt.Println(res)
}
Output:
hello_world

func ToTitle added in v0.0.10

func ToTitle(input string, opts ...any) (string, error)

ToTitle converts an input string (auto-detected format) to Title Case (Smart Title).

func UpperCaseFirst

func UpperCaseFirst(s string) string

UpperCaseFirst uppercases the first character of the string.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "hello world"
	res := strings2.UpperCaseFirst(input)
	fmt.Println(res)
}
Output:
Hello world

func UpperCaseFirstWithErr

func UpperCaseFirstWithErr(s string) (string, error)

UpperCaseFirstWithErr uppercases the first character of the string. It returns an error if the first character is an invalid rune.

func WordLength added in v0.0.3

func WordLength(word Word) (int, error)

WordLength returns the string length of the given Word type without allocating.

func WordsToFormattedCase

func WordsToFormattedCase(words []Word, opts ...any) (string, error)

WordsToFormattedCase generates formatted case strings with the given options

Types

type AcronymWord

type AcronymWord string

AcronymWord is a word that represents an acronym. It is usually preserved in case, but can be configured otherwise.

func (AcronymWord) Len added in v0.0.4

func (w AcronymWord) Len() int

func (AcronymWord) String

func (w AcronymWord) String() string

type BasePart

type BasePart struct {
	Subs []SubPart
}

func (BasePart) String

func (p BasePart) String() string

func (BasePart) SubParts

func (p BasePart) SubParts() []SubPart

type BaseSubPart

type BaseSubPart struct {
	Val rune
}

func (BaseSubPart) IsDigit

func (b BaseSubPart) IsDigit() bool

func (BaseSubPart) IsLetter

func (b BaseSubPart) IsLetter() bool

func (BaseSubPart) IsLower

func (b BaseSubPart) IsLower() bool

func (BaseSubPart) IsSpace

func (b BaseSubPart) IsSpace() bool

func (BaseSubPart) IsSymbol

func (b BaseSubPart) IsSymbol() bool

func (BaseSubPart) IsUpper

func (b BaseSubPart) IsUpper() bool

func (BaseSubPart) Rune

func (b BaseSubPart) Rune() rune

type CaseMode

type CaseMode int

CaseMode defines the casing transformation mode.

const (
	// CMVerbatim leaves the case as is.
	CMVerbatim CaseMode = iota
	// CMFirstTitle uppercases the first character of the first word.
	CMFirstTitle
	// CMAllTitle uppercases the first character of every word.
	CMAllTitle
	// CMFirstLower lowercases the first character of the first word.
	CMFirstLower
	// CMWhispering lowercases all characters (like snake_case or kebab-case usually).
	CMWhispering
	// CMScreaming uppercases all characters (like SCREAMING_SNAKE_CASE).
	CMScreaming
	// CMSmartTitle applies smart title case handling prepositions correctly.
	CMSmartTitle
)

type DelimiterDetector added in v0.0.7

type DelimiterDetector func(subs []SubPart, index int) (length int)

DelimiterDetector detects if a delimiter starts at the given index in subs. It returns the length of the delimiter in subparts (runes), or 0 if no delimiter is found.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "foo::bar--baz"

	// Create a partitioner that looks for specific multi-rune sequences ("::" and "--")
	partitioner := strings2.NewPartitioner(strings2.PartitionerConfig{
		DelimiterDetector: func(subs []strings2.SubPart, index int) int {
			// Look for double colon "::"
			if index+1 < len(subs) && subs[index].Rune() == ':' && subs[index+1].Rune() == ':' {
				return 2
			}
			// Look for double dash "--"
			if index+1 < len(subs) && subs[index].Rune() == '-' && subs[index+1].Rune() == '-' {
				return 2
			}
			return 0
		},
		PreserveSep: true,
	})

	words, _ := strings2.Parse(input, partitioner)
	for i, w := range words {
		fmt.Printf("Word %d: %T %q\n", i, w, w.String())
	}

}
Output:
Word 0: strings2.SingleCaseWord "foo"
Word 1: strings2.SeparatorWord "::"
Word 2: strings2.SingleCaseWord "bar"
Word 3: strings2.SeparatorWord "--"
Word 4: strings2.SingleCaseWord "baz"

type DigitSubPart

type DigitSubPart struct{ BaseSubPart }

type ExactCaseWord

type ExactCaseWord string

ExactCaseWord is a word that preserves its case when stringified.

func (ExactCaseWord) Len added in v0.0.4

func (w ExactCaseWord) Len() int

func (ExactCaseWord) String

func (w ExactCaseWord) String() string

type FirstLowerBehavior added in v0.0.8

type FirstLowerBehavior int

FirstLowerBehavior determines how the first character of the formatted string should be lowercased.

const (
	// FirstLowerNone does not force the first character to be lowercased.
	FirstLowerNone FirstLowerBehavior = iota
	// FirstLowerAlways forces the first character to be lowercased unconditionally.
	FirstLowerAlways
	// FirstLowerSkipEmpty forces the first character to be lowercased, UNLESS the first parsed word is empty.
	FirstLowerSkipEmpty
)

type FirstUpperCaseWord

type FirstUpperCaseWord string

FirstUpperCaseWord is a word that will have its first letter uppercased and the rest lowercased when stringified.

func (FirstUpperCaseWord) Len added in v0.0.4

func (w FirstUpperCaseWord) Len() int

func (FirstUpperCaseWord) String

func (w FirstUpperCaseWord) String() string

type LetterSubPart

type LetterSubPart struct{ BaseSubPart }

type NumberMode added in v0.0.2

type NumberMode int

NumberMode defines the strategy for handling numbers during parsing.

const (
	// NumberModeNone does not perform any special number splitting.
	NumberModeNone NumberMode = iota
	// NumberModeSplitAlways splits on any transition between a letter and a digit.
	NumberModeSplitAlways
	// NumberModeMergeWithWord treats digits as compatible with both preceding and succeeding lowercase letters,
	// preventing splits like 123test -> 123-test.
	NumberModeMergeWithWord
	// NumberModeTreatAsLowercase treats digits exactly as if they were lowercase letters for boundary detection.
	NumberModeTreatAsLowercase
)

type Option

type Option func(*caseConfig)

Options

func OptionCaseMode

func OptionCaseMode(caseMode CaseMode) Option

OptionCaseMode sets the case mode.

func OptionDelimiter

func OptionDelimiter(d string) Option

OptionDelimiter sets the delimiter between words.

func OptionFirstLower

func OptionFirstLower() Option

OptionFirstLower ensures the very first character of the result is lowercase.

func OptionFirstLowerSkipEmpty added in v0.0.8

func OptionFirstLowerSkipEmpty() Option

OptionFirstLowerSkipEmpty behaves like OptionFirstLower, but skips lowercasing if the first parsed word is empty.

func OptionFirstUpper

func OptionFirstUpper() Option

OptionFirstUpper ensures the very first character of the result is uppercase.

func OptionLoose added in v0.0.2

func OptionLoose() Option

OptionLoose sets loose mode, which preserves invalid UTF-8 bytes as-is instead of replacing them.

func OptionMixCaseSupport

func OptionMixCaseSupport() Option

OptionMixCaseSupport enables splitting of mixed case words (e.g. CamelCase) into separate words based on uppercase letters.

func OptionScreaming added in v0.0.8

func OptionScreaming() Option

OptionScreaming ensures all characters are uppercase.

func OptionSmartTitleSkipWords added in v0.0.10

func OptionSmartTitleSkipWords(words ...string) Option

OptionSmartTitleSkipWords sets the words to keep lowercase during CMSmartTitle conversion.

func OptionSmartTitleThreshold added in v0.0.10

func OptionSmartTitleThreshold(f func(wordCount int) float64) Option

OptionSmartTitleThreshold sets a function that defines the ratio of acronyms to words threshold for fallback to title case. For example, if the calculated ratio of acronyms is greater than the threshold returned by this function, words will be treated as standard words (e.g. A_NEW_HOPE -> A New Hope) instead of preserving acronym caps.

func OptionStrict added in v0.0.2

func OptionStrict() Option

OptionStrict sets strict mode, which returns an error if invalid UTF-8 sequences are encountered.

func OptionUpperIndicator

func OptionUpperIndicator(d string) Option

OptionUpperIndicator sets a specific indicator for upper case (often used for double delimiters).

func OptionWhispering added in v0.0.8

func OptionWhispering() Option

OptionWhispering ensures all characters are lowercase.

type ParserConfig

type ParserConfig struct {
	Partitioner Partitioner
	// SmartAcronyms controls whether all-uppercase words (longer than 1 char)
	// should be treated as AcronymWord instead of UpperCaseWord.
	// Defaults to true.
	SmartAcronyms bool
	// NumberMode controls how numbers are handled during word splitting.
	NumberMode NumberMode
	// EmitEmpty controls whether empty parts are emitted for delimiters
	EmitEmpty bool
}

ParserConfig holds configuration for the parsing pipeline.

type ParserEmitEmpty added in v0.0.8

type ParserEmitEmpty bool

ParserEmitEmpty is a typed option for EmitEmpty configuration.

func (ParserEmitEmpty) Apply added in v0.0.8

func (b ParserEmitEmpty) Apply(p *ParserConfig)

type ParserOption

type ParserOption interface {
	Apply(*ParserConfig)
}

ParserOption configures the parser.

func WithCamelCasePartitioner added in v0.0.8

func WithCamelCasePartitioner(opts ...any) ParserOption

WithCamelCasePartitioner creates a ParserOption that splits on case transitions.

func WithKebabCasePartitioner added in v0.0.8

func WithKebabCasePartitioner(opts ...any) ParserOption

WithKebabCasePartitioner creates a ParserOption that splits on hyphen '-'.

func WithNumberMode added in v0.0.2

func WithNumberMode(mode NumberMode) ParserOption

WithNumberMode sets the specific number splitting mode.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "user123profile"
	// Using WithNumberMode to split at digits
	words, _ := strings2.Parse(input, strings2.WithNumberMode(strings2.NumberModeSplitAlways))
	fmt.Println(words)
}
Output:
[user 123 profile]

func WithNumberSplitting

func WithNumberSplitting(enabled bool) ParserOption

WithNumberSplitting enables or disables splitting on letter-digit boundaries. It is equivalent to WithNumberMode(NumberModeSplitAlways) when true, and WithNumberMode(NumberModeNone) when false.

func WithPartitioner

func WithPartitioner(pt Partitioner) ParserOption

WithPartitioner sets a specific partitioner strategy.

func WithSmartAcronyms

func WithSmartAcronyms(enabled bool) ParserOption

WithSmartAcronyms enables or disables smart acronym detection.

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "XMLReader"
	// Using WithSmartAcronyms to separate XML from Reader
	words, _ := strings2.Parse(input, strings2.WithSmartAcronyms(true))
	fmt.Println(words)
}
Output:
[XML Reader]

func WithSnakeCasePartitioner added in v0.0.8

func WithSnakeCasePartitioner(opts ...any) ParserOption

WithSnakeCasePartitioner creates a ParserOption that splits on underscore '_'.

func WithSplitByDelimiter added in v0.0.8

func WithSplitByDelimiter(delim rune, opts ...any) ParserOption

WithSplitByDelimiter creates a ParserOption that splits on a specific rune delimiter.

type ParserSmartAcronyms

type ParserSmartAcronyms bool

ParserSmartAcronyms is a typed option for SmartAcronyms configuration. It allows passing a boolean-like type directly to Parse.

func (ParserSmartAcronyms) Apply

func (b ParserSmartAcronyms) Apply(p *ParserConfig)

type Part

type Part interface {
	String() string
	SubParts() []SubPart
}

Part represents a grouped sequence of SubParts.

func CamelCasePartitioner

func CamelCasePartitioner(subs []SubPart) []Part

CamelCasePartitioner splits on case transitions. Deprecated: Does not support dynamic configuration via options (e.g. EmitEmpty). Use WithCamelCasePartitioner instead.

func KebabCasePartitioner

func KebabCasePartitioner(subs []SubPart) []Part

KebabCasePartitioner splits on hyphen '-'. Deprecated: Does not support dynamic configuration via options (e.g. EmitEmpty). Use WithKebabCasePartitioner instead.

func SnakeCasePartitioner

func SnakeCasePartitioner(subs []SubPart) []Part

SnakeCasePartitioner splits on underscore '_'. Deprecated: Does not support dynamic configuration via options (e.g. EmitEmpty). Use WithSnakeCasePartitioner instead.

func SplitByDelimiter

func SplitByDelimiter(subs []SubPart, delim rune) []Part

SplitByDelimiter is a helper to split SubParts by a specific rune delimiter. Deprecated: Does not support dynamic configuration via options (e.g. EmitEmpty). Use WithSplitByDelimiter instead.

func SubPartsToParts

func SubPartsToParts(subs []SubPart, partitioner Partitioner) []Part

SubPartsToParts converts SubParts to Parts using the provided Partitioner.

type PartMapper added in v0.0.6

type PartMapper func([]Part) []Part

PartMapper applies a mapping function to a slice of Parts.

type Partitioner

type Partitioner func([]SubPart) []Part

Partitioner defines a function that groups SubParts into Parts.

func DetectPartitioner

func DetectPartitioner(stats Stats, config ...*ParserConfig) Partitioner

DetectPartitioner uses stats to guess the best partitioner. config is optional, if provided it uses settings like NumberSplitting.

func NewPartitioner

func NewPartitioner(cfg PartitionerConfig) Partitioner

NewPartitioner creates a partitioner with specific configuration.

Example (CustomFormat)
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	// Inventing a custom format: "Dot.Separated.Values"
	// We want to split by '.' but keep the parts capitalized as is (or handled by classification).
	input := "User.Profile.Settings"

	// Create a partitioner that splits on dot
	partitioner := strings2.NewPartitioner(strings2.PartitionerConfig{
		Delimiters: map[rune]bool{'.': true},
		SplitCamel: true, // Split if there's camel case inside a part
	})

	// Use Parse with the custom partitioner
	words, _ := strings2.Parse(input, partitioner)

	// Convert to Snake Case
	// Using CMWhispering to force lowercase, otherwise ExactCaseWord preserves case by default
	snake, _ := strings2.ToSnakeCase(words, strings2.OptionCaseMode(strings2.CMWhispering))
	fmt.Println(snake)
}
Output:
user_profile_settings

type PartitionerConfig

type PartitionerConfig struct {
	Delimiters        map[rune]bool
	DelimiterDetector DelimiterDetector
	SplitCamel        bool

	NumberMode  NumberMode
	PreserveSep bool // If true, delimiters are returned as SeparatorPart instead of discarded
	EmitEmpty   bool // If true, emits empty WordParts for leading, consecutive, or trailing delimiters
}

type SeparatorPart

type SeparatorPart struct{ BasePart }

type SeparatorWord

type SeparatorWord string

SeparatorWord is a delimiter or separator preserved from the input.

func (SeparatorWord) Len added in v0.0.4

func (w SeparatorWord) Len() int

func (SeparatorWord) String

func (w SeparatorWord) String() string

type SingleCaseWord

type SingleCaseWord string

SingleCaseWord is a word that will be lowercased when stringified.

func (SingleCaseWord) Len added in v0.0.4

func (w SingleCaseWord) Len() int

Len implementations

func (SingleCaseWord) String

func (w SingleCaseWord) String() string

String implementations

type SpaceSubPart

type SpaceSubPart struct{ BaseSubPart }

type Stats

type Stats struct {
	TotalLen int
	Letters  int
	Digits   int
	Spaces   int
	Symbols  int
	Upper    int
	Lower    int

	// Histogram of specific symbols for delimiter detection
	SymbolCounts map[rune]int
}

Stats contains statistics about the scanned string.

type SubPart

type SubPart interface {
	Rune() rune
	IsDigit() bool
	IsLetter() bool
	IsUpper() bool
	IsLower() bool
	IsSpace() bool
	IsSymbol() bool
}

SubPart represents the smallest unit of parsing, typically a single character with its properties.

type SubPartMapper added in v0.0.6

type SubPartMapper func([]SubPart) []SubPart

SubPartMapper applies a mapping function to a slice of SubParts.

type SymbolSubPart

type SymbolSubPart struct{ BaseSubPart }

type UTF8Mode added in v0.0.2

type UTF8Mode int

UTF8Mode defines how to handle invalid UTF-8 sequences.

const (
	// UTF8Replace replaces invalid UTF-8 bytes with utf8.RuneError (U+FFFD).
	UTF8Replace UTF8Mode = iota
	// UTF8Strict returns an error on invalid UTF-8 sequences.
	UTF8Strict
	// UTF8Ignore ignores invalid UTF-8 sequences and preserves the original bytes (best effort).
	UTF8Ignore
)

type UpperCaseWord

type UpperCaseWord string

UpperCaseWord is a word that was originally all uppercase.

func (UpperCaseWord) Len added in v0.0.4

func (w UpperCaseWord) Len() int

func (UpperCaseWord) String

func (w UpperCaseWord) String() string

type Word

type Word fmt.Stringer

Word interface representing a stringer type that can be used in casing conversions.

func ClassifyPart

func ClassifyPart(part Part, config *ParserConfig) Word

ClassifyPart converts a Part into a Word.

func FromCamelToWords

func FromCamelToWords(input string, opts ...any) ([]Word, error)

func FromDarwinToWords added in v0.0.9

func FromDarwinToWords(input string, opts ...any) ([]Word, error)

func FromKebabToWords

func FromKebabToWords(input string, opts ...any) ([]Word, error)

func FromPascalToWords

func FromPascalToWords(input string, opts ...any) ([]Word, error)

func FromSnakeToWords

func FromSnakeToWords(input string, opts ...any) ([]Word, error)

func Parse

func Parse(input string, opts ...any) ([]Word, error)

Parse parses the input string into a slice of Words based on detection or provided options. It follows the pipeline: String -> SubParts -> Parts -> Words.

opts can be: - ParserOption interface - Partitioner function - PartitionerConfig - ParserSmartAcronyms bool

Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	words, _ := strings2.Parse("helloWorld")
	fmt.Println(words)
}
Output:
[hello World]
Example (SmartAcronyms)
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	words, _ := strings2.Parse("XMLReader", strings2.WithSmartAcronyms(true))
	fmt.Println(words)
}
Output:
[XML Reader]
Example (SnakeCase)
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	words, _ := strings2.ParseSnakeCase("hello_world")
	fmt.Println(words)
}
Output:
[hello world]

func ParseCamelCase

func ParseCamelCase(input string, opts ...any) ([]Word, error)

func ParseDarwinCase added in v0.0.9

func ParseDarwinCase(input string, opts ...any) ([]Word, error)

func ParseKebabCase

func ParseKebabCase(input string, opts ...any) ([]Word, error)

func ParseSnakeCase

func ParseSnakeCase(input string, opts ...any) ([]Word, error)
Example
package main

import (
	"fmt"

	"github.com/arran4/strings2"
)

func main() {
	input := "hello_world"
	// ParseSnakeCase assumes a snake case structure
	words, _ := strings2.ParseSnakeCase(input)
	fmt.Println(words)
}
Output:
[hello world]

func PartsToWords

func PartsToWords(parts []Part, config *ParserConfig) []Word

PartsToWords converts Parts to Words using classification logic.

type WordMapper added in v0.0.6

type WordMapper func([]Word) []Word

WordMapper applies a mapping function to a slice of Words.

type WordPart

type WordPart struct{ BasePart }

Concrete Part types

Image Directories

Path Synopsis
cmd
strings2 command
examples
basic command
permutations command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL