/* $Id: pluralize.c,v 1.6 1994/05/14 09:58:20 vax Exp vax $ * purpose: this file does the brunt of the pluralization work. * * $Log: pluralize.c,v $ * Revision 1.6 1994/05/14 09:58:20 vax * Fixed some small syntax errors. * * Revision 1.5 1994/05/14 09:42:00 vax * Modified pluralize_verb to bring it up to date. Added many small * touches (putting *x->*xes back, etc). General speedups with ``len''. * * Revision 1.4 1994/05/10 10:26:08 vax * Added mapping (hash-table) lookup for exceptions. * Filtered out tabs. * Many small speedups. * * Revision 1.3 1994/05/09 22:48:34 vax * I really really fixed the "mosquito"/"domino" bug now. * * Revision 1.2 1994/02/12 11:29:54 vax * Changed this to use un_article (new simul_efun). * * Revision 1.1 1994/02/12 11:28:41 vax * Initial revision * * old stuff: * author: Pinkfish * history: written by pinkfish one day, and modified for the TMI * distribution mudlib by Buddha on 3-14-92. No changes were needed. ;-) * Changelog: * 7 Nov 1993 by VaX#n8 * o General revamp * 18 Jan 1994 VaX#n8 (vax) * o Special cases for "datum" and "sphinx" added. * 27 Jan 1994 VaX#n8 (vax) * o Rule for '*o' -> '*oes' (mosquito -> mosquitoes) fixed. * This is obsolete: * NB: it is always preferable for objects to set their plural using * "set_plural()" (on std/object), but if the relevant programmer hasn't * done so, "query_plural()" (also on std/object) calls this efun for * a hopefully reasonable approximate. objects should _always_ call * call "query_plural()" to get the plural form of an object's "short()", * failure to do so is treason, and subject to punishment by summary * execution. The Computer is your friend. */ #define VOWELS ({'a', 'e', 'i', 'o', 'u'}) mapping pluralize_exceptions = ([ "fish" : "fish", "deer" : "deer", "sheep" : "sheep", "child" : "children", "tooth" : "teeth", "ox" : "oxen", "vax" : "vaxen", "bus" : "buses", "mouse" : "mice", "goose" : "geese", "fife" : "fifes", "staff" : "staves", "dynamo" : "dynamos", "datum" : "data", "sphinx" : "sphinges", "moose" : "moose", ]); string pluralize(string str) { string pre, suf; /* used temporarily in the beginning */ string two, three, retval; int one, len; // used a few times as length of string. if (!stringp(str)) return ""; // first, get rid of articles. pluralized forms never have them ;) str = un_article(str); // len is used later. It's not computed if str is not a string. if ((len = strlen(str)) < 2) return ""; // Deal with "sword of power" -> "swords of power" types (Watcher 09/92) if (sscanf(str, "%s of %s", pre, suf) == 2) return pluralize(pre) + " of " + suf; // Changed on 5-1-95 by Shriekback to include items that have // parentheses strings at the end of its description. // Example: "light saber (off)" gets pluralized to "light sabers (off)" if (sscanf(str, "%s (%s)", pre, suf) == 2) return sprintf("%s (%s)", pluralize(pre), suf); // trap the exceptions to the rules below and special cases. if (stringp(retval=pluralize_exceptions[str])) return retval; // Leto added the next bit, since 'white mouse' became white mouses' while mouse became 'mice' if(sscanf(str,"%s %s",one,two) == 2 ) return one+" "+pluralize(two); one = str[(len - 1)]; two = str[<2..<1]; three = str[<3..<1]; // now handle "rules" ... god I hate english!! // Latin pluralization, I think // *us -> *i (virus -> viri), also radius if (two == "us") return str[0..<3]+"i"; // nouns ending in s, z, x, o, ch, and sh form plural by adding es. // ex: business, six, church, wish, quizz, avocado if ((member_array(one, ({ 's', 'z', 'x', 'o' })) != -1) || (two == "ch") || (two == "sh")) return str + "es"; // *fe -> *ves (knife -> knives) // exception: fife (above) if (two == "fe") return str[0..<3] + "ves"; /* * *f -> *ves (half -> halves) * *ef -> *efs (chef -> chefs) (really a rule for a special case) * *ff -> *ffs (skiff -> skiffs, cliff -> cliffs) * exception: staff (above) */ if (one == 'f') { if (two == "ef" || two == "ff") return str + "s"; return str[0..<2]+"ves"; } // nouns ending in a consonant plus y form the plural by changing: // *y -> *ies (gumby -> gumbies) if (one == 'y' && (member_array(str[len-2], VOWELS) == -1)) return str[0..<2]+"ies"; // *man -> *men (foreman -> foremen) if (three == "man") return str[0..<3] + "en"; // *is -> *es (this is from gordons pluralize ... ) // if (two == "is") return str[0..<3] + "es"; // default, * -> *s return str + "s"; } /* end of pluralize() */ // mudlib: Basis // note: heavily based on Pinkfish's pluralizer (but simplified since this // one isn't meant to handle nouns or articles etc) // Modified by VaX#n8 // Curiously enough, we "pluralize" the verb (add an s) when we don't pluralize // the noun, and vice-versa. For example: // The company pays high taxes. // The companies pay high taxes. string pluralize_verb(string rel) { string two; int i, one, // the first onearacter of rel. len; // used a few times as length of string. if (!stringp(rel)) return ""; // len is used later. It's not computed if rel is not a string. if ((len = strlen(rel)) < 2) return ""; // trap the exceptions to the rules below and special cases. // not really big enough to merit a hash table. switch (rel) { case "half" : return "halves"; case "go" : return "goes"; case "fish" : return "fishes"; case "staff" : return "staves"; } one = rel[len-1]; // two = rel[<2..<1]; two = rel[<2..<1]; // A small rule for a special case below. // wiz -> wizzes if (two == "iz") return rel + "zes"; // Saw this in the TMI-2 version, don't know why. // I personally think it's incorrect, it is for nouns. // iris -> irises // if (two == "is") return rel + "ses"; // verbs, again, can end in x, s, o, ch, sh, or z. // box, hiss, smash, brush if ((member_array(one, ({ 's', 'z', 'x', 'o' })) != -1) || (two == "ch") || (two == "sh")) return rel + "es"; // *fe -> *ves (knife -> knives) // exception: fife (above) if (two == "fe") return rel[0..<3] + "ves"; /* * *f -> *ves (half -> halves) * *ef -> *efs (chef -> chefs) (really a rule for a special case) * *ff -> *ffs (skiff -> skiffs, cliff -> cliffs) */ if (one == 'f') { if (two == "ef" || two == "ff") return rel + "s"; return rel[0..<2]+"ves"; } // *y -> *ies (gumby -> gumbies) if ((one == 'y') && (member_array(rel[len-2], VOWELS) == -1)) { return rel[0..<2] + "ies"; } // default: (* -> *s) return rel + "s"; }