All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.shadow.pluralize.Pluralize.kt Maven / Gradle / Ivy

The newest version!
package com.shadow.pluralize

import com.shadow.pluralize.utils.Plurality
import java.util.regex.Pattern


fun String.pluralize(plurality: Plurality = Plurality.Singular): String {
    if (plurality == Plurality.Plural) return this

    if (plurality == Plurality.Singular)
        return this.pluralizer()

    if (this.singularizer() != this && this.singularizer() + "s" != this &&
            this.singularizer().pluralizer() == this && this.pluralizer() != this)
        return this

    return this.pluralizer()
}

fun String.singularize(plurality: Plurality = Plurality.Plural): String {

    if (plurality == Plurality.Singular) return this

    if (plurality == Plurality.Plural) return this.singularizer()

    if (this.pluralizer() != this && this + "s" != this.pluralizer() &&
            this.pluralizer().singularize() == this && this.singularizer() != this)
        return this

    return this.singularize()
}

fun String.pluralize(count: Int): String {
    if (count > 1)
        return this.pluralize(Plurality.Plural)
    else
        return this.pluralize(Plurality.Singular)
}

fun String.singularize(count: Int): String {
    if (count > 1)
        return this.singularize(Plurality.Plural)
    else
        return this.singularize(Plurality.Singular)
}

private fun String.pluralizer(): String {
    if (unCountable().contains(this.toLowerCase())) return this
    val rule = pluralizeRules().last { Pattern.compile(it.component1(), Pattern.CASE_INSENSITIVE).matcher(this).find() }
    var found = Pattern.compile(rule.component1(), Pattern.CASE_INSENSITIVE).matcher(this).replaceAll(rule.component2())
    val endsWith = exceptions().firstOrNull { this.endsWith(it.component1()) }
    if (endsWith != null) found = this.replace(endsWith.component1(), endsWith.component2())
    val exception = exceptions().firstOrNull() { this.equals(it.component1(), true) }
    if (exception != null) found = exception.component2()
    return found
}

private fun String.singularizer(): String {
    if (unCountable().contains(this.toLowerCase())) {
        return this
    }
    val exceptions = exceptions().firstOrNull() { this.equals(it.component2(), true) }

    if (exceptions != null) {
        return exceptions.component1()
    }
    val endsWith = exceptions().firstOrNull { this.endsWith(it.component2()) }

    if (endsWith != null) return this.replace(endsWith.component2(), endsWith.component1())

    try {
        if (singularizeRules().count {
            Pattern.compile(it.component1(), Pattern.CASE_INSENSITIVE).matcher(this).find()
        } == 0) return this
        val rule = singularizeRules().last {
            Pattern.compile(it.component1(), Pattern.CASE_INSENSITIVE).matcher(this).find()
        }
        return Pattern.compile(rule.component1(), Pattern.CASE_INSENSITIVE).matcher(this).replaceAll(rule.component2())
    } catch(ex: IllegalArgumentException) {
        Exception("Can't singularize this word, could not find a rule to match.")
    }
    return this
}

fun unCountable(): List {
    return listOf("equipment", "information", "rice", "money",
            "species", "series", "fish", "sheep", "aircraft", "bison",
            "flounder", "pliers", "bream",
            "gallows", "proceedings", "breeches", "graffiti", "rabies",
            "britches", "headquarters", "salmon", "carp", "herpes",
            "scissors", "chassis", "high-jinks", "sea-bass", "clippers",
            "homework", "cod", "innings", "shears",
            "contretemps", "jackanapes", "corps", "mackerel",
            "swine", "debris", "measles", "trout", "diabetes", "mews",
            "tuna", "djinn", "mumps", "whiting", "eland", "news",
            "wildebeest", "elk", "pincers", "sugar")
}

fun exceptions(): List> {
    return listOf("person" to "people",
            "man" to "men",
            "goose" to "geese",
            "child" to "children",
            "sex" to "sexes",
            "move" to "moves",
            "stadium" to "stadiums",
            "deer" to "deer",
            "codex" to "codices",
            "murex" to "murices",
            "silex" to "silices",
            "radix" to "radices",
            "helix" to "helices",
            "alumna" to "alumnae",
            "alga" to "algae",
            "vertebra" to "vertebrae",
            "persona" to "personae",
            "stamen" to "stamina",
            "foramen" to "foramina",
            "lumen" to "lumina",
            "afreet" to "afreeti",
            "afrit" to "afriti",
            "efreet" to "efreeti",
            "cherub" to "cherubim",
            "goy" to "goyim",
            "human" to "humans",
            "lumen" to "lumina",
            "seraph" to "seraphim",
            "Alabaman" to "Alabamans",
            "Bahaman" to "Bahamans",
            "Burman" to "Burmans",
            "German" to "Germans",
            "Hiroshiman" to "Hiroshimans",
            "Liman" to "Limans",
            "Nakayaman" to "Nakayamans",
            "Oklahoman" to "Oklahomans",
            "Panaman" to "Panamans",
            "Selman" to "Selmans",
            "Sonaman" to "Sonamans",
            "Tacoman" to "Tacomans",
            "Yakiman" to "Yakimans",
            "Yokohaman" to "Yokohamans",
            "Yuman" to "Yumans", "criterion" to "criteria",
            "perihelion" to "perihelia",
            "aphelion" to "aphelia",
            "phenomenon" to "phenomena",
            "prolegomenon" to "prolegomena",
            "noumenon" to "noumena",
            "organon" to "organa",
            "asyndeton" to "asyndeta",
            "hyperbaton" to "hyperbata",
            "foot" to "feet")
}

fun pluralizeRules(): List> {
    return listOf(
            "$" to "s",
            "s$" to "s",
            "(ax|test)is$" to "$1es",
            "us$" to "i",
            "(octop|vir)us$" to "$1i",
            "(octop|vir)i$" to "$1i",
            "(alias|status)$" to "$1es",
            "(bu)s$" to "$1ses",
            "(buffal|tomat)o$" to "$1oes",
            "([ti])um$" to "$1a",
            "([ti])a$" to "$1a",
            "sis$" to "ses",
            "(,:([^f])fe|([lr])f)$" to "$1$2ves",
            "(hive)$" to "$1s",
            "([^aeiouy]|qu)y$" to "$1ies",
            "(x|ch|ss|sh)$" to "$1es",
            "(matr|vert|ind)ix|ex$" to "$1ices",
            "([m|l])ouse$" to "$1ice",
            "([m|l])ice$" to "$1ice",
            "^(ox)$" to "$1en",
            "(quiz)$" to "$1zes",
            "f$" to "ves",
            "fe$" to "ves",
            "um$" to "a",
            "on$" to "a",
            "tion" to "tions",
            "sion" to "sions")
}

fun singularizeRules(): List> {
    return listOf(
            "s$" to "",
            "(s|si|u)s$" to "$1s",
            "(n)ews$" to "$1ews",
            "([ti])a$" to "$1um",
            "((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$" to "$1$2sis",
            "(^analy)ses$" to "$1sis",
            "(^analy)sis$" to "$1sis",
            "([^f])ves$" to "$1fe",
            "(hive)s$" to "$1",
            "(tive)s$" to "$1",
            "([lr])ves$" to "$1f",
            "([^aeiouy]|qu)ies$" to "$1y",
            "(s)eries$" to "$1eries",
            "(m)ovies$" to "$1ovie",
            "(x|ch|ss|sh)es$" to "$1",
            "([m|l])ice$" to "$1ouse",
            "(bus)es$" to "$1",
            "(o)es$" to "$1",
            "(shoe)s$" to "$1",
            "(cris|ax|test)is$" to "$1is",
            "(cris|ax|test)es$" to "$1is",
            "(octop|vir)i$" to "$1us",
            "(octop|vir)us$" to "$1us",
            "(alias|status)es$" to "$1",
            "(alias|status)$" to "$1",
            "^(ox)en" to "$1",
            "(vert|ind)ices$" to "$1ex",
            "(matr)ices$" to "$1ix",
            "(quiz)zes$" to "$1",
            "a$" to "um",
            "i$" to "us",
            "ae$" to "a")
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy