using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using SubSonic.Utilities;
namespace SubSonic
{
public static class Inflector
{
private static readonly List<InflectorRule> _plurals = new List<InflectorRule>();
private static readonly List<InflectorRule> _singulars = new List<InflectorRule>();
private static readonly List<string> _uncountables = new List<string>();
static Inflector()
{
AddPluralRule("$", "s");
AddPluralRule("s$", "s");
AddPluralRule("(ax|test)is$", "$1es");
AddPluralRule("(octop|vir)us$", "$1i");
AddPluralRule("(alias|status)$", "$1es");
AddPluralRule("(bu)s$", "$1ses");
AddPluralRule("(buffal|tomat)o$", "$1oes");
AddPluralRule("([ti])um$", "$1a");
AddPluralRule("sis$", "ses");
AddPluralRule("(?:([^f])fe|([lr])f)$", "$1$2ves");
AddPluralRule("(hive)$", "$1s");
AddPluralRule("([^aeiouy]|qu)y$", "$1ies");
AddPluralRule("(x|ch|ss|sh)$", "$1es");
AddPluralRule("(matr|vert|ind)ix|ex$", "$1ices");
AddPluralRule("([m|l])ouse$", "$1ice");
AddPluralRule("^(ox)$", "$1en");
AddPluralRule("(quiz)$", "$1zes");
AddSingularRule("s$", "");
AddSingularRule("ss$", "ss");
AddSingularRule("(n)ews$", "$1ews");
AddSingularRule("([ti])a$", "$1um");
AddSingularRule("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
AddSingularRule("(^analy)ses$", "$1sis");
AddSingularRule("([^f])ves$", "$1fe");
AddSingularRule("(hive)s$", "$1");
AddSingularRule("(tive)s$", "$1");
AddSingularRule("([lr])ves$", "$1f");
AddSingularRule("([^aeiouy]|qu)ies$", "$1y");
AddSingularRule("(s)eries$", "$1eries");
AddSingularRule("(m)ovies$", "$1ovie");
AddSingularRule("(x|ch|ss|sh)es$", "$1");
AddSingularRule("([m|l])ice$", "$1ouse");
AddSingularRule("(bus)es$", "$1");
AddSingularRule("(o)es$", "$1");
AddSingularRule("(shoe)s$", "$1");
AddSingularRule("(cris|ax|test)es$", "$1is");
AddSingularRule("(octop|vir)i$", "$1us");
AddSingularRule("(alias|status)$", "$1");
AddSingularRule("(alias|status)es$", "$1");
AddSingularRule("^(ox)en", "$1");
AddSingularRule("(vert|ind)ices$", "$1ex");
AddSingularRule("(matr)ices$", "$1ix");
AddSingularRule("(quiz)zes$", "$1");
AddIrregularRule("person", "people");
AddIrregularRule("man", "men");
AddIrregularRule("child", "children");
AddIrregularRule("sex", "sexes");
AddIrregularRule("tax", "taxes");
AddIrregularRule("move", "moves");
AddUnknownCountRule("equipment");
AddUnknownCountRule("information");
AddUnknownCountRule("rice");
AddUnknownCountRule("money");
AddUnknownCountRule("species");
AddUnknownCountRule("series");
AddUnknownCountRule("fish");
AddUnknownCountRule("sheep");
}
private class InflectorRule
{
public readonly Regex regex;
public readonly string replacement;
public InflectorRule(string regexPattern, string replacementText)
{
regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
replacement = replacementText;
}
public string Apply(string word)
{
if (!regex.IsMatch(word))
{
return null;
}
string replace = regex.Replace(word, replacement);
if(word == word.ToUpper())
{
replace = replace.ToUpper();
}
return replace;
}
}
private static void AddIrregularRule(string singular, string plural)
{
AddPluralRule("(" + singular[0] + ")" + singular.Substring(1) + "$", "$1" + plural.Substring(1));
AddSingularRule("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + singular.Substring(1));
}
private static void AddUnknownCountRule(string word)
{
_uncountables.Add(word.ToLower());
}
private static void AddPluralRule(string rule, string replacement)
{
_plurals.Add(new InflectorRule(rule, replacement));
}
private static void AddSingularRule(string rule, string replacement)
{
_singulars.Add(new InflectorRule(rule, replacement));
}
public static string MakePlural(string word)
{
return ApplyRules(_plurals, word);
}
public static string MakeSingular(string word)
{
return ApplyRules(_singulars, word);
}
private static string ApplyRules(List<InflectorRule> rules, string word)
{
string result = word;
if (!_uncountables.Contains(word.ToLower()))
{
for (int i = rules.Count - 1; i >= 0; i--)
{
string currentPass = rules[i].Apply(word);
if (currentPass != null)
{
result = currentPass;
break;
}
}
}
return result;
}
public static string ToTitleCase(string word)
{
return Regex.Replace(ToHumanCase(AddUnderscores(word)), @"\b([a-z])",
delegate(Match match)
{
return match.Captures[0].Value.ToUpper();
});
}
public static string ToHumanCase(string lowercaseAndUnderscoredWord)
{
return MakeInitialCaps(Regex.Replace(lowercaseAndUnderscoredWord, @"_", " "));
}
public static string ToPascalCase(string lowercaseAndUnderscoredWord)
{
return ToPascalCase(lowercaseAndUnderscoredWord, true);
}
////TODO: What is this supposed to do? It doesn't convert "This Is My Word" to "ThisIsMyWord" -P.H. 2007.02.16
//public static string ToPascalCase(string lowercaseAndUnderscoredWord, bool removeUnderscores) {
// string pattern = "(?:^|_)(.)";
// if (!removeUnderscores)
// pattern = "(?:^)(.)";
// return Regex.Replace(lowercaseAndUnderscoredWord, pattern,
// delegate(Match match) {
// return match.Groups[1].Value.ToUpper();
// });
//}
/// <summary>
/// Converts text to pascal case...
/// </summary>
/// <param name="text"></param>
/// <param name="removeUnderscores"></param>
/// <returns></returns>
public static string ToPascalCase(string text, bool removeUnderscores)
{
if (String.IsNullOrEmpty(text))
return text;
text = text.Replace("_", " ");
string joinString = removeUnderscores ? String.Empty : "_";
string[] words = text.Split(' ');
if (words.Length > 1 || Sugar.Validation.IsUpperCase(words[0]))
{
for (int i = 0; i < words.Length; i++)
{
if (words[i].Length > 0)
{
string word = words[i];
string restOfWord = word.Substring(1);
if(Sugar.Validation.IsUpperCase(restOfWord))
restOfWord = restOfWord.ToLower(CultureInfo.CurrentUICulture);
char firstChar = char.ToUpper(word[0], CultureInfo.CurrentUICulture);
words[i] = firstChar + restOfWord;
}
}
return String.Join(joinString, words);
}
else
{
return words[0].Substring(0, 1).ToUpper(CultureInfo.CurrentUICulture) + words[0].Substring(1);
}
}
public static string ToCamelCase(string lowercaseAndUnderscoredWord)
{
return MakeInitialLowerCase(ToPascalCase(lowercaseAndUnderscoredWord));
}
public static string AddUnderscores(string pascalCasedWord)
{
return Regex.Replace(Regex.Replace(Regex.Replace(pascalCasedWord, @"([A-Z]+)([A-Z][a-z])", "$1_$2"), @"([a-z\d])([A-Z])", "$1_$2"), @"[-\s]", "_").ToLower();
}
public static string MakeInitialCaps(string word)
{
return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower();
}
public static string MakeInitialLowerCase(string word)
{
return word.Substring(0, 1).ToLower() + word.Substring(1);
}
public static string AddOrdinalSuffix(string number)
{
if (Utility.IsStringNumeric(number))
{
int n = int.Parse(number);
int nMod100 = n % 100;
if (nMod100 >= 11 && nMod100 <= 13)
{
return number + "th";
}
switch (n % 10)
{
case 1:
return number + "st";
case 2:
return number + "nd";
case 3:
return number + "rd";
default:
return number + "th";
}
}
return number;
}
public static string ConvertUnderscoresToDashes(string underscoredWord)
{
return underscoredWord.Replace('_', '-');
}
}
}