gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

inflections.go (8234B)


      1 /*
      2 Package inflection pluralizes and singularizes English nouns.
      3 
      4 		inflection.Plural("person") => "people"
      5 		inflection.Plural("Person") => "People"
      6 		inflection.Plural("PERSON") => "PEOPLE"
      7 
      8 		inflection.Singular("people") => "person"
      9 		inflection.Singular("People") => "Person"
     10 		inflection.Singular("PEOPLE") => "PERSON"
     11 
     12 		inflection.Plural("FancyPerson") => "FancydPeople"
     13 		inflection.Singular("FancyPeople") => "FancydPerson"
     14 
     15 Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb)
     16 
     17 If you want to register more rules, follow:
     18 
     19 		inflection.AddUncountable("fish")
     20 		inflection.AddIrregular("person", "people")
     21 		inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses"
     22 		inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS"
     23 */
     24 package inflection
     25 
     26 import (
     27 	"regexp"
     28 	"strings"
     29 )
     30 
     31 type inflection struct {
     32 	regexp  *regexp.Regexp
     33 	replace string
     34 }
     35 
     36 // Regular is a regexp find replace inflection
     37 type Regular struct {
     38 	find    string
     39 	replace string
     40 }
     41 
     42 // Irregular is a hard replace inflection,
     43 // containing both singular and plural forms
     44 type Irregular struct {
     45 	singular string
     46 	plural   string
     47 }
     48 
     49 // RegularSlice is a slice of Regular inflections
     50 type RegularSlice []Regular
     51 
     52 // IrregularSlice is a slice of Irregular inflections
     53 type IrregularSlice []Irregular
     54 
     55 var pluralInflections = RegularSlice{
     56 	{"([a-z])$", "${1}s"},
     57 	{"s$", "s"},
     58 	{"^(ax|test)is$", "${1}es"},
     59 	{"(octop|vir)us$", "${1}i"},
     60 	{"(octop|vir)i$", "${1}i"},
     61 	{"(alias|status)$", "${1}es"},
     62 	{"(bu)s$", "${1}ses"},
     63 	{"(buffal|tomat)o$", "${1}oes"},
     64 	{"([ti])um$", "${1}a"},
     65 	{"([ti])a$", "${1}a"},
     66 	{"sis$", "ses"},
     67 	{"(?:([^f])fe|([lr])f)$", "${1}${2}ves"},
     68 	{"(hive)$", "${1}s"},
     69 	{"([^aeiouy]|qu)y$", "${1}ies"},
     70 	{"(x|ch|ss|sh)$", "${1}es"},
     71 	{"(matr|vert|ind)(?:ix|ex)$", "${1}ices"},
     72 	{"^(m|l)ouse$", "${1}ice"},
     73 	{"^(m|l)ice$", "${1}ice"},
     74 	{"^(ox)$", "${1}en"},
     75 	{"^(oxen)$", "${1}"},
     76 	{"(quiz)$", "${1}zes"},
     77 }
     78 
     79 var singularInflections = RegularSlice{
     80 	{"s$", ""},
     81 	{"(ss)$", "${1}"},
     82 	{"(n)ews$", "${1}ews"},
     83 	{"([ti])a$", "${1}um"},
     84 	{"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$", "${1}sis"},
     85 	{"(^analy)(sis|ses)$", "${1}sis"},
     86 	{"([^f])ves$", "${1}fe"},
     87 	{"(hive)s$", "${1}"},
     88 	{"(tive)s$", "${1}"},
     89 	{"([lr])ves$", "${1}f"},
     90 	{"([^aeiouy]|qu)ies$", "${1}y"},
     91 	{"(s)eries$", "${1}eries"},
     92 	{"(m)ovies$", "${1}ovie"},
     93 	{"(c)ookies$", "${1}ookie"},
     94 	{"(x|ch|ss|sh)es$", "${1}"},
     95 	{"^(m|l)ice$", "${1}ouse"},
     96 	{"(bus)(es)?$", "${1}"},
     97 	{"(o)es$", "${1}"},
     98 	{"(shoe)s$", "${1}"},
     99 	{"(cris|test)(is|es)$", "${1}is"},
    100 	{"^(a)x[ie]s$", "${1}xis"},
    101 	{"(octop|vir)(us|i)$", "${1}us"},
    102 	{"(alias|status)(es)?$", "${1}"},
    103 	{"^(ox)en", "${1}"},
    104 	{"(vert|ind)ices$", "${1}ex"},
    105 	{"(matr)ices$", "${1}ix"},
    106 	{"(quiz)zes$", "${1}"},
    107 	{"(database)s$", "${1}"},
    108 }
    109 
    110 var irregularInflections = IrregularSlice{
    111 	{"person", "people"},
    112 	{"man", "men"},
    113 	{"child", "children"},
    114 	{"sex", "sexes"},
    115 	{"move", "moves"},
    116 	{"mombie", "mombies"},
    117 }
    118 
    119 var uncountableInflections = []string{"equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "jeans", "police"}
    120 
    121 var compiledPluralMaps []inflection
    122 var compiledSingularMaps []inflection
    123 
    124 func compile() {
    125 	compiledPluralMaps = []inflection{}
    126 	compiledSingularMaps = []inflection{}
    127 	for _, uncountable := range uncountableInflections {
    128 		inf := inflection{
    129 			regexp:  regexp.MustCompile("^(?i)(" + uncountable + ")$"),
    130 			replace: "${1}",
    131 		}
    132 		compiledPluralMaps = append(compiledPluralMaps, inf)
    133 		compiledSingularMaps = append(compiledSingularMaps, inf)
    134 	}
    135 
    136 	for _, value := range irregularInflections {
    137 		infs := []inflection{
    138 			inflection{regexp: regexp.MustCompile(strings.ToUpper(value.singular) + "$"), replace: strings.ToUpper(value.plural)},
    139 			inflection{regexp: regexp.MustCompile(strings.Title(value.singular) + "$"), replace: strings.Title(value.plural)},
    140 			inflection{regexp: regexp.MustCompile(value.singular + "$"), replace: value.plural},
    141 		}
    142 		compiledPluralMaps = append(compiledPluralMaps, infs...)
    143 	}
    144 
    145 	for _, value := range irregularInflections {
    146 		infs := []inflection{
    147 			inflection{regexp: regexp.MustCompile(strings.ToUpper(value.plural) + "$"), replace: strings.ToUpper(value.singular)},
    148 			inflection{regexp: regexp.MustCompile(strings.Title(value.plural) + "$"), replace: strings.Title(value.singular)},
    149 			inflection{regexp: regexp.MustCompile(value.plural + "$"), replace: value.singular},
    150 		}
    151 		compiledSingularMaps = append(compiledSingularMaps, infs...)
    152 	}
    153 
    154 	for i := len(pluralInflections) - 1; i >= 0; i-- {
    155 		value := pluralInflections[i]
    156 		infs := []inflection{
    157 			inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)},
    158 			inflection{regexp: regexp.MustCompile(value.find), replace: value.replace},
    159 			inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace},
    160 		}
    161 		compiledPluralMaps = append(compiledPluralMaps, infs...)
    162 	}
    163 
    164 	for i := len(singularInflections) - 1; i >= 0; i-- {
    165 		value := singularInflections[i]
    166 		infs := []inflection{
    167 			inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)},
    168 			inflection{regexp: regexp.MustCompile(value.find), replace: value.replace},
    169 			inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace},
    170 		}
    171 		compiledSingularMaps = append(compiledSingularMaps, infs...)
    172 	}
    173 }
    174 
    175 func init() {
    176 	compile()
    177 }
    178 
    179 // AddPlural adds a plural inflection
    180 func AddPlural(find, replace string) {
    181 	pluralInflections = append(pluralInflections, Regular{find, replace})
    182 	compile()
    183 }
    184 
    185 // AddSingular adds a singular inflection
    186 func AddSingular(find, replace string) {
    187 	singularInflections = append(singularInflections, Regular{find, replace})
    188 	compile()
    189 }
    190 
    191 // AddIrregular adds an irregular inflection
    192 func AddIrregular(singular, plural string) {
    193 	irregularInflections = append(irregularInflections, Irregular{singular, plural})
    194 	compile()
    195 }
    196 
    197 // AddUncountable adds an uncountable inflection
    198 func AddUncountable(values ...string) {
    199 	uncountableInflections = append(uncountableInflections, values...)
    200 	compile()
    201 }
    202 
    203 // GetPlural retrieves the plural inflection values
    204 func GetPlural() RegularSlice {
    205 	plurals := make(RegularSlice, len(pluralInflections))
    206 	copy(plurals, pluralInflections)
    207 	return plurals
    208 }
    209 
    210 // GetSingular retrieves the singular inflection values
    211 func GetSingular() RegularSlice {
    212 	singulars := make(RegularSlice, len(singularInflections))
    213 	copy(singulars, singularInflections)
    214 	return singulars
    215 }
    216 
    217 // GetIrregular retrieves the irregular inflection values
    218 func GetIrregular() IrregularSlice {
    219 	irregular := make(IrregularSlice, len(irregularInflections))
    220 	copy(irregular, irregularInflections)
    221 	return irregular
    222 }
    223 
    224 // GetUncountable retrieves the uncountable inflection values
    225 func GetUncountable() []string {
    226 	uncountables := make([]string, len(uncountableInflections))
    227 	copy(uncountables, uncountableInflections)
    228 	return uncountables
    229 }
    230 
    231 // SetPlural sets the plural inflections slice
    232 func SetPlural(inflections RegularSlice) {
    233 	pluralInflections = inflections
    234 	compile()
    235 }
    236 
    237 // SetSingular sets the singular inflections slice
    238 func SetSingular(inflections RegularSlice) {
    239 	singularInflections = inflections
    240 	compile()
    241 }
    242 
    243 // SetIrregular sets the irregular inflections slice
    244 func SetIrregular(inflections IrregularSlice) {
    245 	irregularInflections = inflections
    246 	compile()
    247 }
    248 
    249 // SetUncountable sets the uncountable inflections slice
    250 func SetUncountable(inflections []string) {
    251 	uncountableInflections = inflections
    252 	compile()
    253 }
    254 
    255 // Plural converts a word to its plural form
    256 func Plural(str string) string {
    257 	for _, inflection := range compiledPluralMaps {
    258 		if inflection.regexp.MatchString(str) {
    259 			return inflection.regexp.ReplaceAllString(str, inflection.replace)
    260 		}
    261 	}
    262 	return str
    263 }
    264 
    265 // Singular converts a word to its singular form
    266 func Singular(str string) string {
    267 	for _, inflection := range compiledSingularMaps {
    268 		if inflection.regexp.MatchString(str) {
    269 			return inflection.regexp.ReplaceAllString(str, inflection.replace)
    270 		}
    271 	}
    272 	return str
    273 }