Golang : Convert word to its plural form example
Here is a program that will convert a singular word into its plural form and at the same time, perform sanity check to see if the word is already pluralized and avoid pluralizing the given word. Although it has two maps to translate couple of special words from singular to plural and back to singular form...by all means the maps are not complete. Feel free to add in those missing words.
Can be useful in enhancing chat bot or simply just to follow the rule of grammar. For my own usage, I need this code to form proper sentence after a computer vision program calculated the number of detect objects.
NOTES: This program purposely avoid using regular expression.
Here you go!
package main
import (
"fmt"
)
var vowels = []string{"a", "e", "i", "o", "u"}
var pluralDictionary = map[string]string{
"is": "are",
"analysis": "analyses",
"alumnus": "alumni",
"alumnae": "alumni",
"atlas": "atlases",
"appendix": "appendices",
"barrack": "barracks",
"beef": "beefs",
"brother": "brothers",
"cafe": "cafes",
"corpus": "corpuses",
"cow": "cows",
"ganglion": "ganglions",
"genus": "genera",
"graffito": "graffiti",
"loaf": "loaves",
"money": "monies",
"mongoose": "mongooses",
"move": "moves",
"mythos": "mythoi",
"niche": "niches",
"numen": "numina",
"octopus": "octopuses",
"opus": "opuses",
"ox": "oxen",
"penis": "penises",
"vagina": "vaginas",
"sex": "sexes",
"testis": "testes",
"turf": "turfs",
"tooth": "teeth",
"foot": "feet",
"cactus": "cacti",
"child": "children",
"criterion": "criteria",
"news": "news",
"datum": "data",
"deer": "deer",
"echo": "echoes",
"elf": "elves",
"embargo": "embargoes",
"foe": "foes",
"focus": "foci",
"fungus": "fungi",
"goose": "geese",
"hero": "heroes",
"hoof": "hooves",
"index": "indices",
"knife": "knives",
"leaf": "leaves",
"life": "lives",
"man": "men",
"mouse": "mice",
"nucleus": "nuclei",
"person": "people",
"phenomenon": "phenomena",
"potato": "potatoes",
"self": "selves",
"syllabus": "syllabi",
"tomato": "tomatoes",
"torpedo": "torpedoes",
"veto": "vetoes",
"woman": "women",
"zero": "zeroes",
}
var singularDictionary = map[string]string{
"are": "is",
"analyses": "analysis",
"alumni": "alumnus",
//"alumni": "alumnae", // for female - cannot have duplicate in map
"genii": "genius",
"data": "datum",
"atlases": "atlas",
"appendices": "appendix",
"barracks": "barrack",
"beefs": "beef",
"brothers": "brother",
"cafes": "cafe",
"corpuses": "corpus",
"cows": "cow",
"ganglions": "ganglion",
"genera": "genus",
"graffiti": "graffito",
"loaves": "loaf",
"monies": "money",
"mongooses": "mongoose",
"moves": "move",
"mythoi": "mythos",
"niches": "niche",
"numina": "numen",
"octopuses": "octopus",
"opuses": "opus",
"oxen": "ox",
"penises": "penis",
"vaginas": "vagina",
"sexes": "sex",
"testes": "testis",
"turfs": "turf",
"teeth": "tooth",
"feet": "foot",
"cacti": "cactus",
"children": "child",
"criteria": "criterion",
"news": "news",
"deer": "deer",
"echoes": "echo",
"elves": "elf",
"embargoes": "embargo",
"foes": "foe",
"foci": "focus",
"fungi": "fungus",
"geese": "goose",
"heroes": "hero",
"hooves": "hoof",
"indices": "index",
"knifes": "knife",
"leaves": "leaf",
"lives": "life",
"men": "man",
"mice": "mouse",
"nuclei": "nucleus",
"people": "person",
"phenomena": "phenomenon",
"potatoes": "potato",
"selves": "self",
"syllabi": "syllabus",
"tomatoes": "tomato",
"torpedoes": "torpedo",
"vetoes": "veto",
"women": "woman",
"zeroes": "zero",
}
//https://www.socketloop.com/tutorials/golang-check-if-item-is-in-slice-array
func inVowels(str string, list []string) bool {
for _, v := range list {
if v == str {
return true
}
}
return false
}
func AlreadyPluralized(test string) bool {
if len(test) != 1 {
// to handle words like genii, data and etc.
if singularDictionary[test] != "" {
return true
}
// put in some exceptions
//if (string(test[len(test)-1]) != "s") || (string(test[len(test)-2]) != "ii") {
if string(test[len(test)-1]) != "s" {
if (string(test[len(test)-1:]) != "e") || (string(test[len(test)-1:]) != "y") {
return false
}
if (string(test[len(test)-2:]) == "ch") || (string(test[len(test)-2:]) == "sh") || (string(test[len(test)-3:]) == "nes") {
return false
}
if string(test[len(test)-3:]) == "ius" {
return false
}
if pluralDictionary[test] == "" {
return true
}
} else {
return true
}
}
return false
}
func Pluralize(singular string) string {
plural := ""
suffix := ""
if singular != "" {
root := singular
// are we dealing with a single character?
if len(singular) == 1 {
return singular + "s"
}
plural = pluralDictionary[singular]
// found an exact match in map
if plural != "" {
return plural
//fmt.Println(plural)
}
// handle -sis
if string(singular[len(singular)-3:]) == "sis" {
root = string(singular[:len(singular)-3])
suffix = "ses"
plural = root + suffix
return plural
}
// handle -z
if string(singular[len(singular)-1:]) == "z" {
root = string(singular[:len(singular)-1])
suffix = "zes"
plural = root + suffix
return plural
}
// handle -ex
if string(singular[len(singular)-2:]) == "ex" {
root = string(singular[:len(singular)-2])
suffix = "ices"
plural = root + suffix
return plural
}
// handle -ix
if string(singular[len(singular)-2:]) == "ix" {
root = string(singular[:len(singular)-2])
suffix = "ices"
plural = root + suffix
return plural
}
// handle -us
if string(singular[len(singular)-2:]) == "us" {
root = string(singular[:len(singular)-2])
suffix = "uses"
plural = root + suffix
return plural
}
// handle word such as dolly
if (string(singular[len(singular)-1]) == "y") && !inVowels(string(singular[len(singular)-2]), vowels) {
root = string(singular[:len(singular)-1])
suffix = "ies"
} else if string(singular[len(singular)-1]) == "s" {
if inVowels(string(singular[len(singular)-2]), vowels) {
if string(singular[len(singular)-3:]) == "ius" {
root = string(singular[:len(singular)-2])
suffix = "i"
} else {
root = string(singular[:len(singular)-1])
suffix = "ses"
}
} else {
suffix = "es"
}
} else if (string(singular[len(singular)-2:]) == "ch") || (string(singular[len(singular)-2:]) == "sh") {
suffix = "es"
} else {
suffix = "s"
}
plural = root + suffix
// sanity check
if AlreadyPluralized(singular) {
return singular
} else {
return plural
}
} else {
return "Singular cannot be empty"
}
}
func main() {
fmt.Println("************************************")
fmt.Println("* convert singular to plural *")
fmt.Println("************************************")
// test empty string
singular := ""
fmt.Println(singular + ":" + Pluralize(singular))
singular = "diagnosis"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "news"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "is"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "series"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "arm"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "status"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "dependency"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "goose"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "dolly"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "datum"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "genius"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "jones"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "tree"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "infantry"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "hero"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "zero"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "tons"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "tonus"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "temple"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "church"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "x"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "triangle"
fmt.Println(singular + ":" + Pluralize(singular))
singular = "colony"
fmt.Println(singular + ":" + Pluralize(singular))
fmt.Println("************************************")
fmt.Println("* sanity check tests on plurals *")
fmt.Println("************************************")
// what if already plural
singular = "triangles"
fmt.Println(singular+":", AlreadyPluralized(singular))
singular = "shiites"
fmt.Println(singular+":", AlreadyPluralized(singular))
singular = "infantries"
fmt.Println(singular+":", AlreadyPluralized(singular))
singular = "torpedoes"
fmt.Println(singular+":", AlreadyPluralized(singular))
singular = "genii"
fmt.Println(singular+":", AlreadyPluralized(singular))
// retrieve the singular form
fmt.Println(singular+" singular form is :", singularDictionary[singular])
singular = "aces"
fmt.Println(singular+":", AlreadyPluralized(singular))
singular = "townies"
fmt.Println(singular+":", AlreadyPluralized(singular))
singular = "data"
fmt.Println(singular+":", AlreadyPluralized(singular))
// retrieve the singular form
fmt.Println(singular+" singular form is :", singularDictionary[singular])
singular = "joneses"
fmt.Println(singular+":", AlreadyPluralized(singular))
}
Sample output:
************************************
* convert singular to plural *
************************************
:Singular cannot be empty
tooth:teeth
foot:feet
head:heads
arm:arms
torpedo:torpedoes
dependency:dependencies
goose:geese
dolly:dollies
datum:data
genius:genius
jones:jones
tree:trees
infantry:infantries
hero:heroes
zero:zeroes
tons:tons
tonus:tonus
temple:temples
church:churches
x:xs
triangle:triangles
colony:colonies
************************************
* sanity check tests on plurals *
************************************
triangles: true
shiites: true
infantries: true
torpedoes: true
genii: true
genii singular form is : genius
aces: true
townies: true
data: true
data singular form is : datum
joneses: true
Happy coding!
References:
https://www.socketloop.com/tutorials/golang-check-if-item-is-in-slice-array
http://code.activestate.com/recipes/577781-pluralize-word-convert-singular-word-to-its-plural/
See also : Golang : Simple word wrap or line breaking example
By Adam Ng
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+9k Golang : Generate EAN barcode
+11k Golang : Fix fmt.Scanf() on Windows will scan input twice problem
+5.6k Unix/Linux : How to test user agents blocked successfully ?
+4.4k Linux : sudo yum updates not working
+13.2k Golang : Get constant name from value
+30.5k Golang : Interpolating or substituting variables in string examples
+4.4k JavaScript : Rounding number to decimal formats to display currency
+22k Golang : Read directory content with filepath.Walk()
+10.7k Nginx : TLS 1.2 support
+13.2k Golang : Get user input until a command or receive a word to stop
+35k Golang : Integer is between a range