summaryrefslogtreecommitdiff
path: root/vendor/github.com/go-openapi/inflect/inflect.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-openapi/inflect/inflect.go')
-rw-r--r--vendor/github.com/go-openapi/inflect/inflect.go713
1 files changed, 713 insertions, 0 deletions
diff --git a/vendor/github.com/go-openapi/inflect/inflect.go b/vendor/github.com/go-openapi/inflect/inflect.go
new file mode 100644
index 000000000..3008844ca
--- /dev/null
+++ b/vendor/github.com/go-openapi/inflect/inflect.go
@@ -0,0 +1,713 @@
+package inflect
+
+import (
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// used by rulesets
+type Rule struct {
+ suffix string
+ replacement string
+ exact bool
+}
+
+// a Ruleset is the config of pluralization rules
+// you can extend the rules with the Add* methods
+type Ruleset struct {
+ uncountables map[string]bool
+ plurals []*Rule
+ singulars []*Rule
+ humans []*Rule
+ acronyms []*Rule
+ acronymMatcher *regexp.Regexp
+}
+
+// create a blank ruleset. Unless you are going to
+// build your own rules from scratch you probably
+// won't need this and can just use the defaultRuleset
+// via the global inflect.* methods
+func NewRuleset() *Ruleset {
+ rs := new(Ruleset)
+ rs.uncountables = make(map[string]bool)
+ rs.plurals = make([]*Rule, 0)
+ rs.singulars = make([]*Rule, 0)
+ rs.humans = make([]*Rule, 0)
+ rs.acronyms = make([]*Rule, 0)
+ return rs
+}
+
+// create a new ruleset and load it with the default
+// set of common English pluralization rules
+func NewDefaultRuleset() *Ruleset {
+ rs := NewRuleset()
+ rs.AddPlural("s", "s")
+ rs.AddPlural("testis", "testes")
+ rs.AddPlural("axis", "axes")
+ rs.AddPlural("octopus", "octopi")
+ rs.AddPlural("virus", "viri")
+ rs.AddPlural("octopi", "octopi")
+ rs.AddPlural("viri", "viri")
+ rs.AddPlural("alias", "aliases")
+ rs.AddPlural("status", "statuses")
+ rs.AddPlural("bus", "buses")
+ rs.AddPlural("buffalo", "buffaloes")
+ rs.AddPlural("tomato", "tomatoes")
+ rs.AddPlural("tum", "ta")
+ rs.AddPlural("ium", "ia")
+ rs.AddPlural("ta", "ta")
+ rs.AddPlural("ia", "ia")
+ rs.AddPlural("sis", "ses")
+ rs.AddPlural("lf", "lves")
+ rs.AddPlural("rf", "rves")
+ rs.AddPlural("afe", "aves")
+ rs.AddPlural("bfe", "bves")
+ rs.AddPlural("cfe", "cves")
+ rs.AddPlural("dfe", "dves")
+ rs.AddPlural("efe", "eves")
+ rs.AddPlural("gfe", "gves")
+ rs.AddPlural("hfe", "hves")
+ rs.AddPlural("ife", "ives")
+ rs.AddPlural("jfe", "jves")
+ rs.AddPlural("kfe", "kves")
+ rs.AddPlural("lfe", "lves")
+ rs.AddPlural("mfe", "mves")
+ rs.AddPlural("nfe", "nves")
+ rs.AddPlural("ofe", "oves")
+ rs.AddPlural("pfe", "pves")
+ rs.AddPlural("qfe", "qves")
+ rs.AddPlural("rfe", "rves")
+ rs.AddPlural("sfe", "sves")
+ rs.AddPlural("tfe", "tves")
+ rs.AddPlural("ufe", "uves")
+ rs.AddPlural("vfe", "vves")
+ rs.AddPlural("wfe", "wves")
+ rs.AddPlural("xfe", "xves")
+ rs.AddPlural("yfe", "yves")
+ rs.AddPlural("zfe", "zves")
+ rs.AddPlural("hive", "hives")
+ rs.AddPlural("quy", "quies")
+ rs.AddPlural("by", "bies")
+ rs.AddPlural("cy", "cies")
+ rs.AddPlural("dy", "dies")
+ rs.AddPlural("fy", "fies")
+ rs.AddPlural("gy", "gies")
+ rs.AddPlural("hy", "hies")
+ rs.AddPlural("jy", "jies")
+ rs.AddPlural("ky", "kies")
+ rs.AddPlural("ly", "lies")
+ rs.AddPlural("my", "mies")
+ rs.AddPlural("ny", "nies")
+ rs.AddPlural("py", "pies")
+ rs.AddPlural("qy", "qies")
+ rs.AddPlural("ry", "ries")
+ rs.AddPlural("sy", "sies")
+ rs.AddPlural("ty", "ties")
+ rs.AddPlural("vy", "vies")
+ rs.AddPlural("wy", "wies")
+ rs.AddPlural("xy", "xies")
+ rs.AddPlural("zy", "zies")
+ rs.AddPlural("x", "xes")
+ rs.AddPlural("ch", "ches")
+ rs.AddPlural("ss", "sses")
+ rs.AddPlural("sh", "shes")
+ rs.AddPlural("matrix", "matrices")
+ rs.AddPlural("vertix", "vertices")
+ rs.AddPlural("indix", "indices")
+ rs.AddPlural("matrex", "matrices")
+ rs.AddPlural("vertex", "vertices")
+ rs.AddPlural("index", "indices")
+ rs.AddPlural("mouse", "mice")
+ rs.AddPlural("louse", "lice")
+ rs.AddPlural("mice", "mice")
+ rs.AddPlural("lice", "lice")
+ rs.AddPluralExact("ox", "oxen", true)
+ rs.AddPluralExact("oxen", "oxen", true)
+ rs.AddPluralExact("quiz", "quizzes", true)
+ rs.AddSingular("s", "")
+ rs.AddSingular("news", "news")
+ rs.AddSingular("ta", "tum")
+ rs.AddSingular("ia", "ium")
+ rs.AddSingular("analyses", "analysis")
+ rs.AddSingular("bases", "basis")
+ rs.AddSingular("diagnoses", "diagnosis")
+ rs.AddSingular("parentheses", "parenthesis")
+ rs.AddSingular("prognoses", "prognosis")
+ rs.AddSingular("synopses", "synopsis")
+ rs.AddSingular("theses", "thesis")
+ rs.AddSingular("analyses", "analysis")
+ rs.AddSingular("aves", "afe")
+ rs.AddSingular("bves", "bfe")
+ rs.AddSingular("cves", "cfe")
+ rs.AddSingular("dves", "dfe")
+ rs.AddSingular("eves", "efe")
+ rs.AddSingular("gves", "gfe")
+ rs.AddSingular("hves", "hfe")
+ rs.AddSingular("ives", "ife")
+ rs.AddSingular("jves", "jfe")
+ rs.AddSingular("kves", "kfe")
+ rs.AddSingular("lves", "lfe")
+ rs.AddSingular("mves", "mfe")
+ rs.AddSingular("nves", "nfe")
+ rs.AddSingular("oves", "ofe")
+ rs.AddSingular("pves", "pfe")
+ rs.AddSingular("qves", "qfe")
+ rs.AddSingular("rves", "rfe")
+ rs.AddSingular("sves", "sfe")
+ rs.AddSingular("tves", "tfe")
+ rs.AddSingular("uves", "ufe")
+ rs.AddSingular("vves", "vfe")
+ rs.AddSingular("wves", "wfe")
+ rs.AddSingular("xves", "xfe")
+ rs.AddSingular("yves", "yfe")
+ rs.AddSingular("zves", "zfe")
+ rs.AddSingular("hives", "hive")
+ rs.AddSingular("tives", "tive")
+ rs.AddSingular("lves", "lf")
+ rs.AddSingular("rves", "rf")
+ rs.AddSingular("quies", "quy")
+ rs.AddSingular("bies", "by")
+ rs.AddSingular("cies", "cy")
+ rs.AddSingular("dies", "dy")
+ rs.AddSingular("fies", "fy")
+ rs.AddSingular("gies", "gy")
+ rs.AddSingular("hies", "hy")
+ rs.AddSingular("jies", "jy")
+ rs.AddSingular("kies", "ky")
+ rs.AddSingular("lies", "ly")
+ rs.AddSingular("mies", "my")
+ rs.AddSingular("nies", "ny")
+ rs.AddSingular("pies", "py")
+ rs.AddSingular("qies", "qy")
+ rs.AddSingular("ries", "ry")
+ rs.AddSingular("sies", "sy")
+ rs.AddSingular("ties", "ty")
+ rs.AddSingular("vies", "vy")
+ rs.AddSingular("wies", "wy")
+ rs.AddSingular("xies", "xy")
+ rs.AddSingular("zies", "zy")
+ rs.AddSingular("series", "series")
+ rs.AddSingular("movies", "movie")
+ rs.AddSingular("xes", "x")
+ rs.AddSingular("ches", "ch")
+ rs.AddSingular("sses", "ss")
+ rs.AddSingular("shes", "sh")
+ rs.AddSingular("mice", "mouse")
+ rs.AddSingular("lice", "louse")
+ rs.AddSingular("buses", "bus")
+ rs.AddSingular("oes", "o")
+ rs.AddSingular("shoes", "shoe")
+ rs.AddSingular("crises", "crisis")
+ rs.AddSingular("axes", "axis")
+ rs.AddSingular("testes", "testis")
+ rs.AddSingular("octopi", "octopus")
+ rs.AddSingular("viri", "virus")
+ rs.AddSingular("statuses", "status")
+ rs.AddSingular("aliases", "alias")
+ rs.AddSingularExact("oxen", "ox", true)
+ rs.AddSingular("vertices", "vertex")
+ rs.AddSingular("indices", "index")
+ rs.AddSingular("matrices", "matrix")
+ rs.AddSingularExact("quizzes", "quiz", true)
+ rs.AddSingular("databases", "database")
+ rs.AddIrregular("person", "people")
+ rs.AddIrregular("man", "men")
+ rs.AddIrregular("child", "children")
+ rs.AddIrregular("sex", "sexes")
+ rs.AddIrregular("move", "moves")
+ rs.AddIrregular("zombie", "zombies")
+ rs.AddUncountable("equipment")
+ rs.AddUncountable("information")
+ rs.AddUncountable("rice")
+ rs.AddUncountable("money")
+ rs.AddUncountable("species")
+ rs.AddUncountable("series")
+ rs.AddUncountable("fish")
+ rs.AddUncountable("sheep")
+ rs.AddUncountable("jeans")
+ rs.AddUncountable("police")
+ return rs
+}
+
+func (rs *Ruleset) Uncountables() map[string]bool {
+ return rs.uncountables
+}
+
+// add a pluralization rule
+func (rs *Ruleset) AddPlural(suffix, replacement string) {
+ rs.AddPluralExact(suffix, replacement, false)
+}
+
+// add a pluralization rule with full string match
+func (rs *Ruleset) AddPluralExact(suffix, replacement string, exact bool) {
+ // remove uncountable
+ delete(rs.uncountables, suffix)
+ // create rule
+ r := new(Rule)
+ r.suffix = suffix
+ r.replacement = replacement
+ r.exact = exact
+ // prepend
+ rs.plurals = append([]*Rule{r}, rs.plurals...)
+}
+
+// add a singular rule
+func (rs *Ruleset) AddSingular(suffix, replacement string) {
+ rs.AddSingularExact(suffix, replacement, false)
+}
+
+// same as AddSingular but you can set `exact` to force
+// a full string match
+func (rs *Ruleset) AddSingularExact(suffix, replacement string, exact bool) {
+ // remove from uncountable
+ delete(rs.uncountables, suffix)
+ // create rule
+ r := new(Rule)
+ r.suffix = suffix
+ r.replacement = replacement
+ r.exact = exact
+ rs.singulars = append([]*Rule{r}, rs.singulars...)
+}
+
+// Human rules are applied by humanize to show more friendly
+// versions of words
+func (rs *Ruleset) AddHuman(suffix, replacement string) {
+ r := new(Rule)
+ r.suffix = suffix
+ r.replacement = replacement
+ rs.humans = append([]*Rule{r}, rs.humans...)
+}
+
+// Add any inconsistant pluralizing/sinularizing rules
+// to the set here.
+func (rs *Ruleset) AddIrregular(singular, plural string) {
+ delete(rs.uncountables, singular)
+ delete(rs.uncountables, plural)
+ rs.AddPlural(singular, plural)
+ rs.AddPlural(plural, plural)
+ rs.AddSingular(plural, singular)
+}
+
+// if you use acronym you may need to add them to the ruleset
+// to prevent Underscored words of things like "HTML" coming out
+// as "h_t_m_l"
+func (rs *Ruleset) AddAcronym(word string) {
+ r := new(Rule)
+ r.suffix = word
+ r.replacement = rs.Titleize(strings.ToLower(word))
+ rs.acronyms = append(rs.acronyms, r)
+}
+
+// add a word to this ruleset that has the same singular and plural form
+// for example: "rice"
+func (rs *Ruleset) AddUncountable(word string) {
+ rs.uncountables[strings.ToLower(word)] = true
+}
+
+func (rs *Ruleset) isUncountable(word string) bool {
+ // handle multiple words by using the last one
+ words := strings.Split(word, " ")
+ if _, exists := rs.uncountables[strings.ToLower(words[len(words)-1])]; exists {
+ return true
+ }
+ return false
+}
+
+// returns the plural form of a singular word
+func (rs *Ruleset) Pluralize(word string) string {
+ if len(word) == 0 {
+ return word
+ }
+ if rs.isUncountable(word) {
+ return word
+ }
+ for _, rule := range rs.plurals {
+ if rule.exact {
+ if word == rule.suffix {
+ return rule.replacement
+ }
+ } else {
+ if strings.HasSuffix(word, rule.suffix) {
+ return replaceLast(word, rule.suffix, rule.replacement)
+ }
+ }
+ }
+ return word + "s"
+}
+
+// returns the singular form of a plural word
+func (rs *Ruleset) Singularize(word string) string {
+ if len(word) == 0 {
+ return word
+ }
+ if rs.isUncountable(word) {
+ return word
+ }
+ for _, rule := range rs.singulars {
+ if rule.exact {
+ if word == rule.suffix {
+ return rule.replacement
+ }
+ } else {
+ if strings.HasSuffix(word, rule.suffix) {
+ return replaceLast(word, rule.suffix, rule.replacement)
+ }
+ }
+ }
+ return word
+}
+
+// uppercase first character
+func (rs *Ruleset) Capitalize(word string) string {
+ return strings.ToUpper(word[:1]) + word[1:]
+}
+
+// "dino_party" -> "DinoParty"
+func (rs *Ruleset) Camelize(word string) string {
+ words := splitAtCaseChangeWithTitlecase(word)
+ return strings.Join(words, "")
+}
+
+// same as Camelcase but with first letter downcased
+func (rs *Ruleset) CamelizeDownFirst(word string) string {
+ word = Camelize(word)
+ return strings.ToLower(word[:1]) + word[1:]
+}
+
+// Captitilize every word in sentance "hello there" -> "Hello There"
+func (rs *Ruleset) Titleize(word string) string {
+ words := splitAtCaseChangeWithTitlecase(word)
+ return strings.Join(words, " ")
+}
+
+func (rs *Ruleset) safeCaseAcronyms(word string) string {
+ // convert an acroymn like HTML into Html
+ for _, rule := range rs.acronyms {
+ word = strings.Replace(word, rule.suffix, rule.replacement, -1)
+ }
+ return word
+}
+
+func (rs *Ruleset) seperatedWords(word, sep string) string {
+ word = rs.safeCaseAcronyms(word)
+ words := splitAtCaseChange(word)
+ return strings.Join(words, sep)
+}
+
+// lowercase underscore version "BigBen" -> "big_ben"
+func (rs *Ruleset) Underscore(word string) string {
+ return rs.seperatedWords(word, "_")
+}
+
+// First letter of sentance captitilized
+// Uses custom friendly replacements via AddHuman()
+func (rs *Ruleset) Humanize(word string) string {
+ word = replaceLast(word, "_id", "") // strip foreign key kinds
+ // replace and strings in humans list
+ for _, rule := range rs.humans {
+ word = strings.Replace(word, rule.suffix, rule.replacement, -1)
+ }
+ sentance := rs.seperatedWords(word, " ")
+ return strings.ToUpper(sentance[:1]) + sentance[1:]
+}
+
+// an underscored foreign key name "Person" -> "person_id"
+func (rs *Ruleset) ForeignKey(word string) string {
+ return rs.Underscore(rs.Singularize(word)) + "_id"
+}
+
+// a foreign key (with an underscore) "Person" -> "personid"
+func (rs *Ruleset) ForeignKeyCondensed(word string) string {
+ return rs.Underscore(word) + "id"
+}
+
+// Rails style pluralized table names: "SuperPerson" -> "super_people"
+func (rs *Ruleset) Tableize(word string) string {
+ return rs.Pluralize(rs.Underscore(rs.Typeify(word)))
+}
+
+var notUrlSafe *regexp.Regexp = regexp.MustCompile(`[^\w\d\-_ ]`)
+
+// param safe dasherized names like "my-param"
+func (rs *Ruleset) Parameterize(word string) string {
+ return ParameterizeJoin(word, "-")
+}
+
+// param safe dasherized names with custom seperator
+func (rs *Ruleset) ParameterizeJoin(word, sep string) string {
+ word = strings.ToLower(word)
+ word = rs.Asciify(word)
+ word = notUrlSafe.ReplaceAllString(word, "")
+ word = strings.Replace(word, " ", sep, -1)
+ if len(sep) > 0 {
+ squash, err := regexp.Compile(sep + "+")
+ if err == nil {
+ word = squash.ReplaceAllString(word, sep)
+ }
+ }
+ word = strings.Trim(word, sep+" ")
+ return word
+}
+
+var lookalikes map[string]*regexp.Regexp = map[string]*regexp.Regexp{
+ "A": regexp.MustCompile(`À|Á|Â|Ã|Ä|Å`),
+ "AE": regexp.MustCompile(`Æ`),
+ "C": regexp.MustCompile(`Ç`),
+ "E": regexp.MustCompile(`È|É|Ê|Ë`),
+ "G": regexp.MustCompile(`Ğ`),
+ "I": regexp.MustCompile(`Ì|Í|Î|Ï|İ`),
+ "N": regexp.MustCompile(`Ñ`),
+ "O": regexp.MustCompile(`Ò|Ó|Ô|Õ|Ö|Ø`),
+ "S": regexp.MustCompile(`Ş`),
+ "U": regexp.MustCompile(`Ù|Ú|Û|Ü`),
+ "Y": regexp.MustCompile(`Ý`),
+ "ss": regexp.MustCompile(`ß`),
+ "a": regexp.MustCompile(`à|á|â|ã|ä|å`),
+ "ae": regexp.MustCompile(`æ`),
+ "c": regexp.MustCompile(`ç`),
+ "e": regexp.MustCompile(`è|é|ê|ë`),
+ "g": regexp.MustCompile(`ğ`),
+ "i": regexp.MustCompile(`ì|í|î|ï|ı`),
+ "n": regexp.MustCompile(`ñ`),
+ "o": regexp.MustCompile(`ò|ó|ô|õ|ö|ø`),
+ "s": regexp.MustCompile(`ş`),
+ "u": regexp.MustCompile(`ù|ú|û|ü|ũ|ū|ŭ|ů|ű|ų`),
+ "y": regexp.MustCompile(`ý|ÿ`),
+}
+
+// transforms latin characters like é -> e
+func (rs *Ruleset) Asciify(word string) string {
+ for repl, regex := range lookalikes {
+ word = regex.ReplaceAllString(word, repl)
+ }
+ return word
+}
+
+var tablePrefix *regexp.Regexp = regexp.MustCompile(`^[^.]*\.`)
+
+// "something_like_this" -> "SomethingLikeThis"
+func (rs *Ruleset) Typeify(word string) string {
+ word = tablePrefix.ReplaceAllString(word, "")
+ return rs.Camelize(rs.Singularize(word))
+}
+
+// "SomeText" -> "some-text"
+func (rs *Ruleset) Dasherize(word string) string {
+ return rs.seperatedWords(word, "-")
+}
+
+// "1031" -> "1031st"
+func (rs *Ruleset) Ordinalize(str string) string {
+ number, err := strconv.Atoi(str)
+ if err != nil {
+ return str
+ }
+ switch abs(number) % 100 {
+ case 11, 12, 13:
+ return fmt.Sprintf("%dth", number)
+ default:
+ switch abs(number) % 10 {
+ case 1:
+ return fmt.Sprintf("%dst", number)
+ case 2:
+ return fmt.Sprintf("%dnd", number)
+ case 3:
+ return fmt.Sprintf("%drd", number)
+ }
+ }
+ return fmt.Sprintf("%dth", number)
+}
+
+/////////////////////////////////////////
+// the default global ruleset
+//////////////////////////////////////////
+
+var defaultRuleset *Ruleset
+
+func init() {
+ defaultRuleset = NewDefaultRuleset()
+}
+
+func Uncountables() map[string]bool {
+ return defaultRuleset.Uncountables()
+}
+
+func AddPlural(suffix, replacement string) {
+ defaultRuleset.AddPlural(suffix, replacement)
+}
+
+func AddSingular(suffix, replacement string) {
+ defaultRuleset.AddSingular(suffix, replacement)
+}
+
+func AddHuman(suffix, replacement string) {
+ defaultRuleset.AddHuman(suffix, replacement)
+}
+
+func AddIrregular(singular, plural string) {
+ defaultRuleset.AddIrregular(singular, plural)
+}
+
+func AddAcronym(word string) {
+ defaultRuleset.AddAcronym(word)
+}
+
+func AddUncountable(word string) {
+ defaultRuleset.AddUncountable(word)
+}
+
+func Pluralize(word string) string {
+ return defaultRuleset.Pluralize(word)
+}
+
+func Singularize(word string) string {
+ return defaultRuleset.Singularize(word)
+}
+
+func Capitalize(word string) string {
+ return defaultRuleset.Capitalize(word)
+}
+
+func Camelize(word string) string {
+ return defaultRuleset.Camelize(word)
+}
+
+func CamelizeDownFirst(word string) string {
+ return defaultRuleset.CamelizeDownFirst(word)
+}
+
+func Titleize(word string) string {
+ return defaultRuleset.Titleize(word)
+}
+
+func Underscore(word string) string {
+ return defaultRuleset.Underscore(word)
+}
+
+func Humanize(word string) string {
+ return defaultRuleset.Humanize(word)
+}
+
+func ForeignKey(word string) string {
+ return defaultRuleset.ForeignKey(word)
+}
+
+func ForeignKeyCondensed(word string) string {
+ return defaultRuleset.ForeignKeyCondensed(word)
+}
+
+func Tableize(word string) string {
+ return defaultRuleset.Tableize(word)
+}
+
+func Parameterize(word string) string {
+ return defaultRuleset.Parameterize(word)
+}
+
+func ParameterizeJoin(word, sep string) string {
+ return defaultRuleset.ParameterizeJoin(word, sep)
+}
+
+func Typeify(word string) string {
+ return defaultRuleset.Typeify(word)
+}
+
+func Dasherize(word string) string {
+ return defaultRuleset.Dasherize(word)
+}
+
+func Ordinalize(word string) string {
+ return defaultRuleset.Ordinalize(word)
+}
+
+func Asciify(word string) string {
+ return defaultRuleset.Asciify(word)
+}
+
+// helper funcs
+
+func reverse(s string) string {
+ o := make([]rune, utf8.RuneCountInString(s))
+ i := len(o)
+ for _, c := range s {
+ i--
+ o[i] = c
+ }
+ return string(o)
+}
+
+func isSpacerChar(c rune) bool {
+ switch {
+ case c == rune("_"[0]):
+ return true
+ case c == rune(" "[0]):
+ return true
+ case c == rune(":"[0]):
+ return true
+ case c == rune("-"[0]):
+ return true
+ }
+ return false
+}
+
+func splitAtCaseChange(s string) []string {
+ words := make([]string, 0)
+ word := make([]rune, 0)
+ for _, c := range s {
+ spacer := isSpacerChar(c)
+ if len(word) > 0 {
+ if unicode.IsUpper(c) || spacer {
+ words = append(words, string(word))
+ word = make([]rune, 0)
+ }
+ }
+ if !spacer {
+ word = append(word, unicode.ToLower(c))
+ }
+ }
+ words = append(words, string(word))
+ return words
+}
+
+func splitAtCaseChangeWithTitlecase(s string) []string {
+ words := make([]string, 0)
+ word := make([]rune, 0)
+ for _, c := range s {
+ spacer := isSpacerChar(c)
+ if len(word) > 0 {
+ if unicode.IsUpper(c) || spacer {
+ words = append(words, string(word))
+ word = make([]rune, 0)
+ }
+ }
+ if !spacer {
+ if len(word) > 0 {
+ word = append(word, unicode.ToLower(c))
+ } else {
+ word = append(word, unicode.ToUpper(c))
+ }
+ }
+ }
+ words = append(words, string(word))
+ return words
+}
+
+func replaceLast(s, match, repl string) string {
+ // reverse strings
+ srev := reverse(s)
+ mrev := reverse(match)
+ rrev := reverse(repl)
+ // match first and reverse back
+ return reverse(strings.Replace(srev, mrev, rrev, 1))
+}
+
+func abs(x int) int {
+ if x < 0 {
+ return -x
+ }
+ return x
+}