Culture Aware Validation

It is easy to display a decimal number for any culture in .Net. The formatting support is very comprehensive and you can fine tune it in a number of different ways to suite your particular needs. But how is it to validate a string representing a decimal number from potential any culture with a wide variety of formatting rules? For example, the following strings are the same decimal value displayed according to different cultures: 1,234.56, 1.234,65, 1 234.56 and 1’234.56

In C# I can use the Parse or TryParse method of the numeric type. I tried these for decimal numbers and noticed some unexpected behavior. For the “en-US” culture the decimal separator is a dot. When parsing the string “1.2”, I received the decimal value 1.2, but when parsing “1,2” the function returned 12! I was expecting an error for this string and wonder why I received a value 10 times time greater than the one I intended to write?

After some investigation I learned that comma is the group separator and can be used in an arbitrary way, for example the string “,,,1,,,2,,,” will also be evaluated to 12. I was not so comfortable with this and from my perspective a valid decimal string should look like the formatted string you receive from, for example, the ToString method.

When the framework doesn’t give you the support you want, you have to implement it yourself. I wanted to use a regular expression to validate decimal numbers from any culture in a stricter way. The difference between different representations is the sign for decimal and group separator. .Net framework includes functions that returns current cultures signs. My solution was to create the regular expression dynamically so I could build it during runtime for the culture in use.

string groupSeparator = Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberGroupSeparator;
string decimalSepartor = Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator;
string regularExpression = @"^\d{1,3}([" + groupSeparator + @"]\d{3})*([" + decimalSepartor + @"]\d+)?$";

Actually, I’m a bit reluctant to create my own regular expression, since I’m not sure I know all different formats. It is also easy to make a mistake and preferable I would like to use what is include in the framework. If I find a better way, I will use it instead!