|
| 1 | +using System.Collections; |
| 2 | +using System.Text.RegularExpressions; |
| 3 | + |
| 4 | +namespace Migrator.Framework.Support |
| 5 | +{ |
| 6 | + public class Inflector |
| 7 | + { |
| 8 | + private static readonly ArrayList plurals = new ArrayList(); |
| 9 | + private static readonly ArrayList singulars = new ArrayList(); |
| 10 | + private static readonly ArrayList uncountables = new ArrayList(); |
| 11 | + |
| 12 | + private Inflector() |
| 13 | + { |
| 14 | + } |
| 15 | + |
| 16 | + static Inflector() |
| 17 | + { |
| 18 | + AddPlural("$", "s"); |
| 19 | + AddPlural("s$", "s"); |
| 20 | + AddPlural("(ax|test)is$", "$1es"); |
| 21 | + AddPlural("(octop|vir)us$", "$1i"); |
| 22 | + AddPlural("(alias|status)$", "$1es"); |
| 23 | + AddPlural("(bu)s$", "$1ses"); |
| 24 | + AddPlural("(buffal|tomat)o$", "$1oes"); |
| 25 | + AddPlural("([ti])um$", "$1a"); |
| 26 | + AddPlural("sis$", "ses"); |
| 27 | + AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves"); |
| 28 | + AddPlural("(hive)$", "$1s"); |
| 29 | + AddPlural("([^aeiouy]|qu)y$", "$1ies"); |
| 30 | + AddPlural("(x|ch|ss|sh)$", "$1es"); |
| 31 | + AddPlural("(matr|vert|ind)ix|ex$", "$1ices"); |
| 32 | + AddPlural("([m|l])ouse$", "$1ice"); |
| 33 | + AddPlural("^(ox)$", "$1en"); |
| 34 | + AddPlural("(quiz)$", "$1zes"); |
| 35 | + AddSingular("s$", ""); |
| 36 | + AddSingular("(n)ews$", "$1ews"); |
| 37 | + AddSingular("([ti])a$", "$1um"); |
| 38 | + AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis"); |
| 39 | + AddSingular("(^analy)ses$", "$1sis"); |
| 40 | + AddSingular("([^f])ves$", "$1fe"); |
| 41 | + AddSingular("(hive)s$", "$1"); |
| 42 | + AddSingular("(tive)s$", "$1"); |
| 43 | + AddSingular("([lr])ves$", "$1f"); |
| 44 | + AddSingular("([^aeiouy]|qu)ies$", "$1y"); |
| 45 | + AddSingular("(s)eries$", "$1eries"); |
| 46 | + AddSingular("(m)ovies$", "$1ovie"); |
| 47 | + AddSingular("(x|ch|ss|sh)es$", "$1"); |
| 48 | + AddSingular("([m|l])ice$", "$1ouse"); |
| 49 | + AddSingular("(bus)es$", "$1"); |
| 50 | + AddSingular("(o)es$", "$1"); |
| 51 | + AddSingular("(shoe)s$", "$1"); |
| 52 | + AddSingular("(cris|ax|test)es$", "$1is"); |
| 53 | + AddSingular("(octop|vir)i$", "$1us"); |
| 54 | + AddSingular("(alias|status)es$", "$1"); |
| 55 | + AddSingular("^(ox)en", "$1"); |
| 56 | + AddSingular("(vert|ind)ices$", "$1ex"); |
| 57 | + AddSingular("(matr)ices$", "$1ix"); |
| 58 | + AddSingular("(quiz)zes$", "$1"); |
| 59 | + AddIrregular("person", "people"); |
| 60 | + AddIrregular("man", "men"); |
| 61 | + AddIrregular("child", "children"); |
| 62 | + AddIrregular("sex", "sexes"); |
| 63 | + AddIrregular("move", "moves"); |
| 64 | + AddUncountable("equipment"); |
| 65 | + AddUncountable("information"); |
| 66 | + AddUncountable("rice"); |
| 67 | + AddUncountable("money"); |
| 68 | + AddUncountable("species"); |
| 69 | + AddUncountable("series"); |
| 70 | + AddUncountable("fish"); |
| 71 | + AddUncountable("sheep"); |
| 72 | + } |
| 73 | + |
| 74 | + private class Rule |
| 75 | + { |
| 76 | + private readonly Regex regex; |
| 77 | + private readonly string replacement; |
| 78 | + |
| 79 | + public Rule(string pattern, string replacement) |
| 80 | + { |
| 81 | + regex = new Regex(pattern, RegexOptions.IgnoreCase); |
| 82 | + this.replacement = replacement; |
| 83 | + } |
| 84 | + |
| 85 | + public string Apply(string word) |
| 86 | + { |
| 87 | + if (!regex.IsMatch(word)) |
| 88 | + { |
| 89 | + return null; |
| 90 | + } |
| 91 | + |
| 92 | + return regex.Replace(word, replacement); |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + /// <summary> |
| 97 | + /// Return the plural of a word. |
| 98 | + /// </summary> |
| 99 | + /// <param name="word">The singular form</param> |
| 100 | + /// <returns>The plural form of <paramref name="word"/></returns> |
| 101 | + public static string Pluralize(string word) |
| 102 | + { |
| 103 | + return ApplyRules(plurals, word); |
| 104 | + } |
| 105 | + |
| 106 | + /// <summary> |
| 107 | + /// Return the singular of a word. |
| 108 | + /// </summary> |
| 109 | + /// <param name="word">The plural form</param> |
| 110 | + /// <returns>The singular form of <paramref name="word"/></returns> |
| 111 | + public static string Singularize(string word) |
| 112 | + { |
| 113 | + return ApplyRules(singulars, word); |
| 114 | + } |
| 115 | + |
| 116 | + /// <summary> |
| 117 | + /// Capitalizes a word. |
| 118 | + /// </summary> |
| 119 | + /// <param name="word">The word to be capitalized.</param> |
| 120 | + /// <returns><paramref name="word"/> capitalized.</returns> |
| 121 | + public static string Capitalize(string word) |
| 122 | + { |
| 123 | + return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower(); |
| 124 | + } |
| 125 | + |
| 126 | + private static void AddIrregular(string singular, string plural) |
| 127 | + { |
| 128 | + AddPlural("(" + singular[0] + ")" + singular.Substring(1) + "$", "$1" + plural.Substring(1)); |
| 129 | + AddSingular("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + singular.Substring(1)); |
| 130 | + } |
| 131 | + |
| 132 | + private static void AddUncountable(string word) |
| 133 | + { |
| 134 | + uncountables.Add(word.ToLower()); |
| 135 | + } |
| 136 | + |
| 137 | + private static void AddPlural(string rule, string replacement) |
| 138 | + { |
| 139 | + plurals.Add(new Rule(rule, replacement)); |
| 140 | + } |
| 141 | + |
| 142 | + private static void AddSingular(string rule, string replacement) |
| 143 | + { |
| 144 | + singulars.Add(new Rule(rule, replacement)); |
| 145 | + } |
| 146 | + |
| 147 | + private static string ApplyRules(IList rules, string word) |
| 148 | + { |
| 149 | + string result = word; |
| 150 | + |
| 151 | + if (!uncountables.Contains(word.ToLower())) |
| 152 | + { |
| 153 | + for (int i = rules.Count - 1; i >= 0; i--) |
| 154 | + { |
| 155 | + Rule rule = (Rule)rules[i]; |
| 156 | + |
| 157 | + if ((result = rule.Apply(word)) != null) |
| 158 | + { |
| 159 | + break; |
| 160 | + } |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + return result; |
| 165 | + } |
| 166 | + } |
| 167 | +} |
0 commit comments