101 lines
1.9 KiB
Go
101 lines
1.9 KiB
Go
|
package text
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
"unicode"
|
||
|
)
|
||
|
|
||
|
// Format lets you transform the text in supported methods while keeping escape
|
||
|
// sequences in the string intact and untouched.
|
||
|
type Format int
|
||
|
|
||
|
// Format enumerations
|
||
|
const (
|
||
|
FormatDefault Format = iota // default_Case
|
||
|
FormatLower // lower
|
||
|
FormatTitle // Title
|
||
|
FormatUpper // UPPER
|
||
|
)
|
||
|
|
||
|
// Apply converts the text as directed.
|
||
|
func (tc Format) Apply(text string) string {
|
||
|
switch tc {
|
||
|
case FormatLower:
|
||
|
return strings.ToLower(text)
|
||
|
case FormatTitle:
|
||
|
return toTitle(text)
|
||
|
case FormatUpper:
|
||
|
return toUpper(text)
|
||
|
default:
|
||
|
return text
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func toTitle(text string) string {
|
||
|
prev, inEscSeq := ' ', false
|
||
|
return strings.Map(
|
||
|
func(r rune) rune {
|
||
|
if r == EscapeStartRune {
|
||
|
inEscSeq = true
|
||
|
}
|
||
|
if !inEscSeq {
|
||
|
if isSeparator(prev) {
|
||
|
prev = r
|
||
|
r = unicode.ToUpper(r)
|
||
|
} else {
|
||
|
prev = r
|
||
|
}
|
||
|
}
|
||
|
if inEscSeq && r == EscapeStopRune {
|
||
|
inEscSeq = false
|
||
|
}
|
||
|
return r
|
||
|
},
|
||
|
text,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func toUpper(text string) string {
|
||
|
inEscSeq := false
|
||
|
return strings.Map(
|
||
|
func(r rune) rune {
|
||
|
if r == EscapeStartRune {
|
||
|
inEscSeq = true
|
||
|
}
|
||
|
if !inEscSeq {
|
||
|
r = unicode.ToUpper(r)
|
||
|
}
|
||
|
if inEscSeq && r == EscapeStopRune {
|
||
|
inEscSeq = false
|
||
|
}
|
||
|
return r
|
||
|
},
|
||
|
text,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// isSeparator returns true if the given rune is a separator. This function is
|
||
|
// lifted straight out of the standard library @ strings/strings.go.
|
||
|
func isSeparator(r rune) bool {
|
||
|
// ASCII alphanumerics and underscore are not separators
|
||
|
if r <= 0x7F {
|
||
|
switch {
|
||
|
case '0' <= r && r <= '9':
|
||
|
return false
|
||
|
case 'a' <= r && r <= 'z':
|
||
|
return false
|
||
|
case 'A' <= r && r <= 'Z':
|
||
|
return false
|
||
|
case r == '_':
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
// Letters and digits are not separators
|
||
|
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
||
|
return false
|
||
|
}
|
||
|
// Otherwise, all we can do for now is treat spaces as separators.
|
||
|
return unicode.IsSpace(r)
|
||
|
}
|