189 lines
5.5 KiB
Go
189 lines
5.5 KiB
Go
|
// Copyright © 2016 Abcum Ltd
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
package lang
|
||
|
|
||
|
import (
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
type inflection struct {
|
||
|
regexp *regexp.Regexp
|
||
|
replace string
|
||
|
}
|
||
|
|
||
|
// Regular is a regexp find replace inflection
|
||
|
type Regular struct {
|
||
|
find string
|
||
|
replace string
|
||
|
}
|
||
|
|
||
|
// Irregular is a hard replace inflection,
|
||
|
// containing both singular and plural forms
|
||
|
type Irregular struct {
|
||
|
singular string
|
||
|
plural string
|
||
|
}
|
||
|
|
||
|
// RegularSlice is a slice of Regular inflections
|
||
|
type RegularSlice []Regular
|
||
|
|
||
|
// IrregularSlice is a slice of Irregular inflections
|
||
|
type IrregularSlice []Irregular
|
||
|
|
||
|
var pluralInflections = RegularSlice{
|
||
|
{"([a-z])$", "${1}s"},
|
||
|
{"s$", "s"},
|
||
|
{"^(ax|test)is$", "${1}es"},
|
||
|
{"(octop|vir)us$", "${1}i"},
|
||
|
{"(octop|vir)i$", "${1}i"},
|
||
|
{"(alias|status)$", "${1}es"},
|
||
|
{"(bu)s$", "${1}ses"},
|
||
|
{"(buffal|tomat)o$", "${1}oes"},
|
||
|
{"([ti])um$", "${1}a"},
|
||
|
{"([ti])a$", "${1}a"},
|
||
|
{"sis$", "ses"},
|
||
|
{"(?:([^f])fe|([lr])f)$", "${1}${2}ves"},
|
||
|
{"(hive)$", "${1}s"},
|
||
|
{"([^aeiouy]|qu)y$", "${1}ies"},
|
||
|
{"(x|ch|ss|sh)$", "${1}es"},
|
||
|
{"(matr|vert|ind)(?:ix|ex)$", "${1}ices"},
|
||
|
{"^(m|l)ouse$", "${1}ice"},
|
||
|
{"^(m|l)ice$", "${1}ice"},
|
||
|
{"^(ox)$", "${1}en"},
|
||
|
{"^(oxen)$", "${1}"},
|
||
|
{"(quiz)$", "${1}zes"},
|
||
|
}
|
||
|
|
||
|
var singularInflections = RegularSlice{
|
||
|
{"s$", ""},
|
||
|
{"(ss)$", "${1}"},
|
||
|
{"(n)ews$", "${1}ews"},
|
||
|
{"([ti])a$", "${1}um"},
|
||
|
{"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$", "${1}sis"},
|
||
|
{"(^analy)(sis|ses)$", "${1}sis"},
|
||
|
{"([^f])ves$", "${1}fe"},
|
||
|
{"(hive)s$", "${1}"},
|
||
|
{"(tive)s$", "${1}"},
|
||
|
{"([lr])ves$", "${1}f"},
|
||
|
{"([^aeiouy]|qu)ies$", "${1}y"},
|
||
|
{"(s)eries$", "${1}eries"},
|
||
|
{"(m)ovies$", "${1}ovie"},
|
||
|
{"(c)ookies$", "${1}ookie"},
|
||
|
{"(x|ch|ss|sh)es$", "${1}"},
|
||
|
{"^(m|l)ice$", "${1}ouse"},
|
||
|
{"(bus)(es)?$", "${1}"},
|
||
|
{"(o)es$", "${1}"},
|
||
|
{"(shoe)s$", "${1}"},
|
||
|
{"(cris|test)(is|es)$", "${1}is"},
|
||
|
{"^(a)x[ie]s$", "${1}xis"},
|
||
|
{"(octop|vir)(us|i)$", "${1}us"},
|
||
|
{"(alias|status)(es)?$", "${1}"},
|
||
|
{"^(ox)en", "${1}"},
|
||
|
{"(vert|ind)ices$", "${1}ex"},
|
||
|
{"(matr)ices$", "${1}ix"},
|
||
|
{"(quiz)zes$", "${1}"},
|
||
|
{"(database)s$", "${1}"},
|
||
|
}
|
||
|
|
||
|
var irregularInflections = IrregularSlice{
|
||
|
{"person", "people"},
|
||
|
{"man", "men"},
|
||
|
{"child", "children"},
|
||
|
{"sex", "sexes"},
|
||
|
{"move", "moves"},
|
||
|
{"mombie", "mombies"},
|
||
|
{"criterion", "criteria"},
|
||
|
}
|
||
|
|
||
|
var uncountableInflections = []string{"equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "jeans", "police"}
|
||
|
|
||
|
var compiledPlurals []inflection
|
||
|
var compiledSingles []inflection
|
||
|
|
||
|
func init() {
|
||
|
|
||
|
compiledPlurals = []inflection{}
|
||
|
compiledSingles = []inflection{}
|
||
|
|
||
|
for _, uncountable := range uncountableInflections {
|
||
|
inf := inflection{
|
||
|
regexp: regexp.MustCompile("^(?i)(" + uncountable + ")$"),
|
||
|
replace: "${1}",
|
||
|
}
|
||
|
compiledPlurals = append(compiledPlurals, inf)
|
||
|
compiledSingles = append(compiledSingles, inf)
|
||
|
}
|
||
|
|
||
|
for _, value := range irregularInflections {
|
||
|
infs := []inflection{
|
||
|
{regexp: regexp.MustCompile(strings.ToUpper(value.singular) + "$"), replace: strings.ToUpper(value.plural)},
|
||
|
{regexp: regexp.MustCompile(strings.Title(value.singular) + "$"), replace: strings.Title(value.plural)},
|
||
|
{regexp: regexp.MustCompile(value.singular + "$"), replace: value.plural},
|
||
|
}
|
||
|
compiledPlurals = append(compiledPlurals, infs...)
|
||
|
}
|
||
|
|
||
|
for _, value := range irregularInflections {
|
||
|
infs := []inflection{
|
||
|
{regexp: regexp.MustCompile(strings.ToUpper(value.plural) + "$"), replace: strings.ToUpper(value.singular)},
|
||
|
{regexp: regexp.MustCompile(strings.Title(value.plural) + "$"), replace: strings.Title(value.singular)},
|
||
|
{regexp: regexp.MustCompile(value.plural + "$"), replace: value.singular},
|
||
|
}
|
||
|
compiledSingles = append(compiledSingles, infs...)
|
||
|
}
|
||
|
|
||
|
for i := len(pluralInflections) - 1; i >= 0; i-- {
|
||
|
value := pluralInflections[i]
|
||
|
infs := []inflection{
|
||
|
{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)},
|
||
|
{regexp: regexp.MustCompile(value.find), replace: value.replace},
|
||
|
{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace},
|
||
|
}
|
||
|
compiledPlurals = append(compiledPlurals, infs...)
|
||
|
}
|
||
|
|
||
|
for i := len(singularInflections) - 1; i >= 0; i-- {
|
||
|
value := singularInflections[i]
|
||
|
infs := []inflection{
|
||
|
{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)},
|
||
|
{regexp: regexp.MustCompile(value.find), replace: value.replace},
|
||
|
{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace},
|
||
|
}
|
||
|
compiledSingles = append(compiledSingles, infs...)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Plural converts a word to its plural form
|
||
|
func Pluralize(str string) string {
|
||
|
for _, inflection := range compiledPlurals {
|
||
|
if inflection.regexp.MatchString(str) {
|
||
|
return inflection.regexp.ReplaceAllString(str, inflection.replace)
|
||
|
}
|
||
|
}
|
||
|
return str
|
||
|
}
|
||
|
|
||
|
// Singular converts a word to its singular form
|
||
|
func Singularize(str string) string {
|
||
|
for _, inflection := range compiledSingles {
|
||
|
if inflection.regexp.MatchString(str) {
|
||
|
return inflection.regexp.ReplaceAllString(str, inflection.replace)
|
||
|
}
|
||
|
}
|
||
|
return str
|
||
|
}
|