I would probably set up a list of rules that are specified in order of preference, this way you can plug rules in by precedence. You can then parse the list based on regex matches returning the correct rule.
A quick prototype would be very easy to set up similar to:
public class FormatRule
{
public string Pattern { get; set; }
public CultureInfo Culture { get; set; }
public FormatRule(string pattern, CultureInfo culture)
{
Pattern = pattern;
Culture = culture;
}
}
Now a list of of FormatRule used to store your rules in order of precedence:
List<FormatRule> Rules = new List<FormatRule>()
{
/* Add rules in order of precedence specifying a culture
* that can handle the pattern, I've chosen en-US and fr-FR
* for this example, but equally any culture could be swapped
* in for various formats you may need to use */
new FormatRule(@"^0.\d+$", CultureInfo.GetCultureInfo("en-US")),
new FormatRule(@"^0,\d+$", CultureInfo.GetCultureInfo("fr-FR")),
new FormatRule(@"^[1-9]+.\d{4,}$", CultureInfo.GetCultureInfo("en-US")),
new FormatRule(@"^[1-9]+,\d{4,}$", CultureInfo.GetCultureInfo("fr-FR")),
new FormatRule(@"^-?[1-9]{1,3}(,\d{3,})*(\.\d*)?$", CultureInfo.GetCultureInfo("en-US")),
new FormatRule(@"^-?[1-9]{1,3}(.\d{3,})*(\,\d*)?$", CultureInfo.GetCultureInfo("fr-FR")),
/* The default rule */
new FormatRule(string.Empty, CultureInfo.CurrentCulture)
}
You should then be able to iterate your list looking for the correct rule to apply:
public CultureInfo FindProvider(string numberString)
{
foreach(FormatRule rule in Rules)
{
if (Regex.IsMatch(numberString, rule.Pattern))
return rule.Culture;
}
return Rules[Rules.Count - 1].Culture;
}
This setup allows you to easily manage rules and set precedence on when something should be handled one way or another. It also allows you to be able to specify different cultures to handle one format one way and a different format another.
public float ParseValue(string valueString)
{
float value = 0;
NumberStyles style = NumberStyles.Any;
IFormatProvider provider = FindCulture(valueString).NumberFormat;
if (float.TryParse(numberString, style, provider, out value))
return value;
else
throw new InvalidCastException(string.Format("Value '{0}' cannot be parsed with any of the providers in the rule set.", valueString));
}
Finally, call your ParseValue() method to convert the string value you have to a float:
string numberString = "-123,456.78"; //Or "23.457.234,87"
float value = ParseValue(numberString);
You may decide to use a dictionary to save on the extra FormatRule class; the concept is the same... I used a list in the example because it makes it easier to query use LINQ. Also, you could easily replace the float type I've used for single, double or decimal if needed.