Improve and add exceptions for singular method by slawekjaranowski · Pull Request #493 · codehaus-plexus/modello (original) (raw)

    private static final Map<String, String> PLURAL_EXCEPTIONS = new HashMap<>();

    static {
        // Irregular plurals
        PLURAL_EXCEPTIONS.put("men", "man");
        PLURAL_EXCEPTIONS.put("women", "woman");
        PLURAL_EXCEPTIONS.put("children", "child");
        PLURAL_EXCEPTIONS.put("mice", "mouse");
        PLURAL_EXCEPTIONS.put("people", "person");
        PLURAL_EXCEPTIONS.put("teeth", "tooth");
        PLURAL_EXCEPTIONS.put("feet", "foot");
        PLURAL_EXCEPTIONS.put("geese", "goose");

        // Invariant plurals
        PLURAL_EXCEPTIONS.put("series", "series");
        PLURAL_EXCEPTIONS.put("species", "species");
        PLURAL_EXCEPTIONS.put("sheep", "sheep");
        PLURAL_EXCEPTIONS.put("fish", "fish");
        PLURAL_EXCEPTIONS.put("deer", "deer");
        PLURAL_EXCEPTIONS.put("aircraft", "aircraft");

        // Special "oes" exceptions
        PLURAL_EXCEPTIONS.put("heroes", "hero");
        PLURAL_EXCEPTIONS.put("potatoes", "potato");
        PLURAL_EXCEPTIONS.put("tomatoes", "tomato");
        PLURAL_EXCEPTIONS.put("echoes", "echo");
        PLURAL_EXCEPTIONS.put("vetoes", "veto");
        PLURAL_EXCEPTIONS.put("torpedoes", "torpedo");
        PLURAL_EXCEPTIONS.put("cargoes", "cargo");
        PLURAL_EXCEPTIONS.put("haloes", "halo");
        PLURAL_EXCEPTIONS.put("mosquitoes", "mosquito");
        PLURAL_EXCEPTIONS.put("buffaloes", "buffalo");
    }

    public static String singular(String plural) {
        if (plural == null || plural.isEmpty()) return plural;

        String lower = plural.toLowerCase();

        if (PLURAL_EXCEPTIONS.containsKey(lower)) {
            return PLURAL_EXCEPTIONS.get(lower);
        }

        // Suffix-based rules
        if (lower.endsWith("ies") && plural.length() > 3) {
            return plural.substring(0, plural.length() - 3) + "y";
        }
        if (lower.endsWith("ves")) {
            return plural.substring(0, plural.length() - 3) + "f";
        }
        if (lower.endsWith("zzes")) {
            return plural.substring(0, plural.length() - 2);
        }
        if (lower.endsWith("sses")) {
            return plural.substring(0, plural.length() - 2);
        }
        if (lower.endsWith("ches") || lower.endsWith("shes")) {
            return plural.substring(0, plural.length() - 2);
        }
        if (lower.endsWith("xes")) {
            return plural.substring(0, plural.length() - 2);
        }
        if (lower.endsWith("oes")) {
            return plural.substring(0, plural.length() - 1);
        }
        if (lower.endsWith("s") && plural.length() > 1) {
            return plural.substring(0, plural.length() - 1);
        }

        return plural;
    }
    // Known exceptions
    "men", "man",
    "women", "woman",
    "children", "child",
    "mice", "mouse",
    "people", "person",
    "teeth", "tooth",
    "feet", "foot",
    "geese", "goose",

    "series", "series",
    "species", "species",
    "sheep", "sheep",
    "fish", "fish",
    "deer", "deer",
    "aircraft", "aircraft",

    "heroes", "hero",
    "potatoes", "potato",
    "tomatoes", "tomato",
    "echoes", "echo",
    "vetoes", "veto",
    "torpedoes", "torpedo",
    "cargoes", "cargo",
    "haloes", "halo",
    "mosquitoes", "mosquito",
    "buffaloes", "buffalo",

    // Regular plural forms with suffixes
    "voes", "voe",
    "hoes", "hoe",
    "canoes", "canoe",
    "toes", "toe",
    "foes", "foe",
    "oboes", "oboe",
    "noes", "no",
    "boxes", "box",
    "wishes", "wish",
    "dishes", "dish",
    "brushes", "brush",
    "classes", "class",
    "buzzes", "buzz",
    "cars", "car",
    "dogs", "dog",
    "cats", "cat",
    "horses", "horse",

    // Some test cases with different rules
    "wolves", "wolf",
    "knives", "knife",
    "leaves", "leaf",
    "wives", "wife",
    "lives", "life",
    "babies", "baby",
    "parties", "party",
    "cities", "city",
    "buses", "bus",
    "boxes", "box",
    "churches", "church",
    "matches", "match",
    "watches", "watch",
    "riches", "rich",
    "dresses", "dress",
    "crosses", "cross",

    // More edge cases
    "heroes", "hero",
    "vetoes", "veto",
    "torpedoes", "torpedo",
    "tomatoes", "tomato",
    "potatoes", "potato",
    "echoes", "echo",
    "mosquitoes", "mosquito",
    "buffaloes", "buffalo",
    "volcanoes", "volcano",
    "goes", "go"