PageRenderTime 3070ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/Centro.Core/Inflector/Inflections.cs

https://github.com/jdaigle/Centro
C# | 271 lines | 213 code | 34 blank | 24 comment | 15 complexity | 0185442865d261b2ea04f30923dbf63f MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text.RegularExpressions;
  5. using Centro.Extensions;
  6. namespace Centro.Inflector
  7. {
  8. public class Inflections
  9. {
  10. private static Inflections defaultInstance;
  11. public static Inflections Default
  12. {
  13. get
  14. {
  15. if (defaultInstance == null)
  16. defaultInstance = new Inflections();
  17. return defaultInstance;
  18. }
  19. }
  20. private readonly IList<Rule> plurals = new List<Rule>();
  21. private readonly IList<Rule> singulars = new List<Rule>();
  22. private readonly IList<string> uncountables = new List<string>();
  23. private Inflections()
  24. {
  25. }
  26. static Inflections()
  27. {
  28. Default.AddPlural("$", "s");
  29. Default.AddPlural("s$", "s");
  30. Default.AddPlural("(ax|test)is$", "$1es");
  31. Default.AddPlural("(octop|vir)us$", "$1i");
  32. Default.AddPlural("(alias|status)$", "$1es");
  33. Default.AddPlural("(bu)s$", "$1ses");
  34. Default.AddPlural("(buffal|tomat)o$", "$1oes");
  35. Default.AddPlural("([ti])um$", "$1a");
  36. Default.AddPlural("sis$", "ses");
  37. Default.AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves");
  38. Default.AddPlural("(hive)$", "$1s");
  39. Default.AddPlural("([^aeiouy]|qu)y$", "$1ies");
  40. Default.AddPlural("(x|ch|ss|sh)$", "$1es");
  41. Default.AddPlural("(matr|vert|ind)ix|ex$", "$1ices");
  42. Default.AddPlural("([m|l])ouse$", "$1ice");
  43. Default.AddPlural("^(ox)$", "$1en");
  44. Default.AddPlural("(quiz)$", "$1zes");
  45. Default.AddSingular("s$", "");
  46. Default.AddSingular("(n)ews$", "$1ews");
  47. Default.AddSingular("([ti])a$", "$1um");
  48. Default.AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
  49. Default.AddSingular("(^analy)ses$", "$1sis");
  50. Default.AddSingular("([^f])ves$", "$1fe");
  51. Default.AddSingular("(hive)s$", "$1");
  52. Default.AddSingular("(tive)s$", "$1");
  53. Default.AddSingular("([lr])ves$", "$1f");
  54. Default.AddSingular("([^aeiouy]|qu)ies$", "$1y");
  55. Default.AddSingular("(s)eries$", "$1eries");
  56. Default.AddSingular("(m)ovies$", "$1ovie");
  57. Default.AddSingular("(x|ch|ss|sh)es$", "$1");
  58. Default.AddSingular("([m|l])ice$", "$1ouse");
  59. Default.AddSingular("(bus)es$", "$1");
  60. Default.AddSingular("(o)es$", "$1");
  61. Default.AddSingular("(shoe)s$", "$1");
  62. Default.AddSingular("(cris|ax|test)es$", "$1is");
  63. Default.AddSingular("(octop|vir)i$", "$1us");
  64. Default.AddSingular("(alias|status)es$", "$1");
  65. Default.AddSingular("^(ox)en", "$1");
  66. Default.AddSingular("(vert|ind)ices$", "$1ex");
  67. Default.AddSingular("(matr)ices$", "$1ix");
  68. Default.AddSingular("(quiz)zes$", "$1");
  69. Default.AddSingular("(database)s$", "$1");
  70. Default.AddIrregular("person", "people");
  71. Default.AddIrregular("man", "men");
  72. Default.AddIrregular("child", "children");
  73. Default.AddIrregular("sex", "sexes");
  74. Default.AddIrregular("move", "moves");
  75. Default.AddIrregular("cow", "kine");
  76. Default.AddUncountable("equipment");
  77. Default.AddUncountable("information");
  78. Default.AddUncountable("rice");
  79. Default.AddUncountable("money");
  80. Default.AddUncountable("species");
  81. Default.AddUncountable("series");
  82. Default.AddUncountable("fish");
  83. Default.AddUncountable("sheep");
  84. }
  85. public void AddPlural(string regexPattern, string replacement)
  86. {
  87. uncountables.Remove(regexPattern);
  88. uncountables.Remove(replacement);
  89. plurals.Add(new Rule(regexPattern, replacement));
  90. }
  91. public void AddSingular(string regexPattern, string replacement)
  92. {
  93. uncountables.Remove(regexPattern);
  94. uncountables.Remove(replacement);
  95. singulars.Add(new Rule(regexPattern, replacement));
  96. }
  97. public void AddUncountable(string word)
  98. {
  99. if (!uncountables.Contains(word.ToUpper()))
  100. uncountables.Add(word.ToUpper());
  101. }
  102. public void AddIrregular(string singular, string plural)
  103. {
  104. uncountables.Remove(singular);
  105. uncountables.Remove(plural);
  106. if (singular.Substring(0, 1).Matches(plural.Substring(0, 1)))
  107. {
  108. AddPlural("(" + singular[0] + ")" + singular.Substring(1) + "$", "$1" + plural.Substring(1));
  109. AddPlural("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + plural.Substring(1));
  110. AddSingular("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + singular.Substring(1));
  111. }
  112. else
  113. {
  114. AddPlural("(" + singular.Substring(0, 1).ToUpper() + ")" + singular.Substring(1) + "$", plural.Substring(0, 1).ToUpper() + plural.Substring(1));
  115. AddPlural("(" + singular.Substring(0, 1).ToLower() + ")" + singular.Substring(1) + "$", plural.Substring(0, 1).ToLower() + plural.Substring(1));
  116. AddPlural("(" + plural.Substring(0, 1).ToUpper() + ")" + plural.Substring(1) + "$", plural.Substring(0, 1).ToUpper() + plural.Substring(1));
  117. AddPlural("(" + plural.Substring(0, 1).ToLower() + ")" + plural.Substring(1) + "$", plural.Substring(0, 1).ToLower() + plural.Substring(1));
  118. AddSingular("(" + plural.Substring(0, 1).ToUpper() + ")" + plural.Substring(1) + "$", singular.Substring(0, 1).ToUpper() + singular.Substring(1));
  119. AddSingular("(" + plural.Substring(0, 1).ToLower() + ")" + plural.Substring(1) + "$", singular.Substring(0, 1).ToLower() + singular.Substring(1));
  120. }
  121. }
  122. public string Pluralize(string word)
  123. {
  124. if (string.IsNullOrEmpty(word) || uncountables.Contains(word.ToUpper()))
  125. return word;
  126. return ApplyRules(plurals, word);
  127. }
  128. public string Singularize(string word)
  129. {
  130. if (string.IsNullOrEmpty(word) || uncountables.Contains(word.ToUpper()))
  131. return word;
  132. return ApplyRules(singulars, word);
  133. }
  134. public string Humanize(string word)
  135. {
  136. return Capitalize(word.Replace("_", " "));
  137. }
  138. public string Capitalize(string word)
  139. {
  140. return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower();
  141. }
  142. public string Camelize(string word, bool firstLetterIsUppercase)
  143. {
  144. if (firstLetterIsUppercase)
  145. return Pascalize(word);
  146. //return word.Substitute("(^|_)(?<letter>.)", m => m.Groups["letter"].Value.ToUpper());
  147. var camelized = Camelize(word, true);
  148. return camelized.ToCharArray().First().ToString().ToLower() + camelized.Substring(1, camelized.Length - 1);
  149. }
  150. public string Pascalize(string lowercaseAndUnderscoredWord)
  151. {
  152. return lowercaseAndUnderscoredWord.Substitute("(?:^|_)(.)", m => m.Groups[1].Value.ToUpper());
  153. }
  154. public string Titleize(string word)
  155. {
  156. return Humanize(Underscore(word)).Substitute(@"\b([a-z])", m => m.Captures[0].Value.ToUpper());
  157. //return Humanize(Underscore(word)).Substitute("('?[a-z])(?<letter>.)", m => m.Groups["letter"].Value.ToUpper());
  158. //return Regex.Replace(Humanize(Underscore(word)), @"\b([a-z])",
  159. // delegate(Match match)
  160. // {
  161. // return match.Captures[0].Value.ToUpper();
  162. // });
  163. }
  164. public string Uncapitalize(string word)
  165. {
  166. return word.Substring(0, 1).ToLower() + word.Substring(1);
  167. }
  168. public string Underscore(string word)
  169. {
  170. return word.Substitute(@"([A-Z]+)([A-Z][a-z])", "$1_$2")
  171. .Substitute(@"([a-z\d])([A-Z])", "$1_$2")
  172. .Substitute(@"[-\s]", "_")
  173. .ToLower();
  174. }
  175. public string Dasherize(string word)
  176. {
  177. return word.Replace(' ', '-').Replace('_', '-');
  178. }
  179. public string Ordinalize(string word)
  180. {
  181. var number = 0;
  182. if (!int.TryParse(word, out number))
  183. throw new ArgumentException("Word must be an integer", "word");
  184. if ((new List<int> { 11, 12, 13 }).Contains(number % 100))
  185. return number.ToString() + "th";
  186. else
  187. switch (number % 10)
  188. {
  189. case 1: return number.ToString() + "st";
  190. case 2: return number.ToString() + "nd";
  191. case 3: return number.ToString() + "rd";
  192. default: return number.ToString() + "th";
  193. }
  194. // int n = int.Parse(number);
  195. // int nMod100 = n%100;
  196. // if (nMod100 >= 11 && nMod100 <= 13)
  197. // {
  198. // return number + "th";
  199. // }
  200. // switch (n%10)
  201. // {
  202. // case 1:
  203. // return number + "st";
  204. // case 2:
  205. // return number + "nd";
  206. // case 3:
  207. // return number + "rd";
  208. // default:
  209. // return number + "th";
  210. // }
  211. }
  212. private string ApplyRules(IList<Rule> rules, string word)
  213. {
  214. var result = word;
  215. foreach (var rule in rules.Reverse())
  216. if ((result = rule.Apply(word)) != null)
  217. return result;
  218. return result;
  219. }
  220. private class Rule
  221. {
  222. private readonly Regex regex;
  223. private readonly string replacement;
  224. public Rule(string regexPattern, string replacement)
  225. {
  226. regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
  227. this.replacement = replacement;
  228. }
  229. public string Apply(string word)
  230. {
  231. if (!regex.IsMatch(word))
  232. return null;
  233. return regex.Replace(word, replacement);
  234. }
  235. }
  236. }
  237. }