Comma and (decimal) point: Do they need different handling? - c#

Just something that i was wondering about.
In Europe the comma us mostly used for decimals (like 20,001) but outside Europe the point is mostly used (like 20.001)
How does c# handle this ?
In case of a application that will be used by Europe and non-Europe people, do you need to worry about the above when programming ?
Just curious about this.

As far as the programming language is concerned, the decimal point separator is always ., and the punctuation used to separate function arguments is always ,. Changing that based on the spoken language of the programmer would be too confusing.
For the user interface, there are formatting functions in the CultureInfo class that can produce a floating point number representation that uses the decimal point separator and thousands separator of your choice. (Or, for cultures that group digits of a number differently than in triplets, the formatting functions can handle that too.)

CultureInfo handles that situation.
Take a look at this
// format float to string
float num = 1.5f;
string str = num.ToString(CultureInfo.InvariantCulture.NumberFormat); // "1.5"
string str = num.ToString(CultureInfo.GetCultureInfo("de-DE").NumberFormat); // "1,5"

Yes, c# (and really, the whole .NET framework) have the concept of Cultures for this purpose:
http://msdn.microsoft.com/en-us/library/bz9tc508.aspx
and
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(v=VS.100).aspx

You should use CultureInfo Class to handle it. Just read and write with correct formatter.

That depends on what exactly you do... .NET is usually aware of the current settings of the machine/OS and uses those...
You should look into this and see whether any of it is relevant in your case...

Related

Currency localization and handling in C#

I am looking for a strategy to implement different currencies in my system.
For GB I use pounds locale and it works ok with numbers like "7.55", but as soon I change locale to Spanish for example I get the "7,55" number and I cannot handle it.
So the first thing is that I calculate some amount with JavaScript client side and JavaScript cannot calculate comma numbers, nor I can parseFloat, nor converting to decimal number if I don't replace commas with numbers like:
input.val().replace(',', '.');
I mean I don't understand how to handle this properly in scenarios when you have to make payment. When to convert for calculations, etc.
Is there any proper way to do this in .net with JavaScript help? Just need some tips.
In c#, you can use CultureInfo.InvariantCulture for this. You have a full snippet about currency here.
string str = "42.5";
float numFloat = float.Parse(str, CultureInfo.InvariantCulture);
Learn more from the msdn.

How to safely and correctly convert a number from user input to double?

This is, basically, a CultureInfo problem. Formally, in my country, the decimal separator is a comma (,) and a thousands separator is a dot (.). In practice, however, this is only used by accountants and diligent people. Normally people never use a thousands separator, and they use both a comma and a dot interchangeably as a decimal separator. I've seen this being the problem even in some Excel spreadsheets that I received from other people, with Excel not having recognized a dot as a decimal separator, leaving the field formatted as a string, rather than a number.
My "solution" thus far has been to simply replace all commas in user input with dots and then parsing the double with InvariantCulture, like so:
string userInput;
...
userInput = userInput.Replace(',', '.');
double result;
double.TryParse(userInput, NumberStyles.Float, CultureInfo.InvariantCulture, out result);
This will obviously fail when someone actually enters the thousands separator and this seems to me more like a hack than a real solution. So, other than making my own parser for doubles, are there any cleaner ways to handle this problem?
If you are using ASP.Net you can use the AjaxControlToolkit FilteredTextBox you can also accomplish the task using regular expressions and pattern matching. It is nearly always better to try and get a standard input than attempting to deal with every possible human input variable.
Some other links:
MaskedTextBox
WPF Tools FilteredTextBox
If there are rules that can conclusively determine what they meant, then you can code the logic. With this problem, though, it is impossible to know the intent in every case:
1,001 === 1.001 or 1001
Also, even though any "better" logic might assume that numbers like "1,01" are unambiguous, such an entry might be a typo of "1,001." How likely this is depends on what kind of data you're gathering.
If people rarely use a thousands separator, then your existing logic seems good. If you want to be 100% certain of intent, though, the only way to be sure is to ask them what they meant in such cases. E.g. if someone enters 1,001 or 1.001 then fail validation, but recode it as "1,001.0" (or .00 if dealing with currency) to disambiguate it, forcing them to resumbit it.
In practice, you probably would cause more harm than good with this kind of abundance of caution since people don't really use the thousands separator. I'd stick with what you got.

Is Int32.ToString() culture-specific?

I'm running a beta version of ReSharper, and it's giving me warnings for the following code:
int id;
// ...
DoSomethingWith(id.ToString());
The warning is on the id.ToString() call, and it's telling me "Specify a culture in string conversion explicitly". I understand the warning, and I know how to fix it -- just change the code to the much more unwieldy id.ToString(CultureInfo.InvariantCulture).
But my question is: is that necessary? I mean, obviously it's important to specify the culture when you're using types like DateTime (different cultures have different date formats) and Double (different characters used for the decimal point). But Int32.ToString(), at least in the en-US and invariant cultures, doesn't add any formatting at all. No commas, no decimal points, no dollar signs, nothing. So what would there be to vary by culture?
Are there some cultures that actually add some sort of formatting when you call the parameterless Int32.ToString()? Or is this a bug in the ReSharper beta, and this warning really isn't applicable to Int32 (in which case I'll file a ReSharper bug report)?
The Operating System allows to change the negative sign for numbers.
Control panel ->
Language and regional settings ->
Additional settings ->
Negative sign
So, current culture could have overridden the negative sign. In this case you need to respect the regional settings, this is the reason of the warning. You can also change the negative sign programatically:
CultureInfo culture = Thread.CurrentThread.CurrentCulture;
// Make a writable clone
culture = (CultureInfo) culture.Clone();
culture.NumberFormat.NegativeSign = "!";
As tested on a random sample of ints, all 352 cultures installed with Windows (CultureTypes.InstalledWin32Cultures) give identical results.
Daniel is right to note a custom culture could use a different prefix for negative numbers, but I doubt anyone has ever used this feature save by accident.
I guess the .NET devs did it to be consistent with float and other types. What else were they expecting?
> int.MaxValue.ToString(CultureInfo.AncientRome)
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM....
It's weird; I would have expected 50.ToString(CultureInfo.CreateSpecificCulture("ar-AE")) to return "٥٠", but it doesn't.
I've just looked this up, and the problem seems to be that NumberFormatInfo.DigitSubstitution isn't actually implemented
The DigitSubstitution property is reserved for future use. Currently, it is not used in either parsing or formatting operations for the current NumberFormatInfo object.
So, although there is an enumeration System.Globalization.DigitShapes, it's not actually implemented in the NumberFormatInfo bit of IFormatProvider.
Yes. It depends on the current culture. From the MSDN docs:
The return value is formatted with the general numeric format specifier ("G") and the NumberFormatInfo object for the current culture.
emphasis mine
Resharper just most likely wants you to be explicit about what culture you are intending to use. Since omitting it relies on behavior that may change when executed on different machines.
The compiler is (unnecessarily) warning us about it COULD be casted to string somehow not as we expected it to be. For example:
int i = 1;
Console.WriteLine("i.ToString='{0}'", i.ToString());
We all expect it to return as '1' but it is not 100% guaranteed because .ToString() method gets affected by the current thread culture. It CLAIMS that it could return as '1.00' or something like that but I tested it with a really small code:
foreach(CultureInfo ci In System.Globalization.CultureInfo.GetCultures(CultureTypes.AllCultures) {
Console.WriteLine("RESULT='{0}' CultureCode: {1} EnglishName:{2}", i.ToString(ci), ci.Name, ci.EnglishName);
if (!i.ToString(ci).Equals("1"))
throw new FormatException()
}
The code never returned any error. So, it actually never returns anything other than "1".
As far as there will be a new country with a brand new native super-weirdo language in this world that actually spells "1.00" for an integer, we can keep using just .ToString() without any doubt.
Cheers!
Output was:
I would have said no, but on checking MSDN Int32.ToString() there's this:
The return value is formatted with the general numeric format specifier ("G") and the NumberFormatInfo object for the current culture.
So there's a surprise.
The question should be why doesn't the current Resharper suggest this?
Because integers can be be as high as 2,147,483,647.
In some countries, they would use decimals or a space in place of the commas.

Avoiding localiztion on formatting numbers written to file

I have a program that sometimes is used in locales that use commas for the decimal separator. Its nice how C# handles all that (good for the UI), but when I export to a file, I need to always use a ".", not the locale specific number. Currently, I do:
String.Format("{0:0.####},{1:0.####}", x, y)
Problem is that in some locales, that ends up using commas instead of periods. Question is, is there a format code that says "always use period", or is the only solution to mess with one's locale?
Simply use:
String.Format(CultureInfo.InvariantCulture, "{0:0.####},{1:0.####}", x, y)
I'd recommend trying FxCop (or the Code Analysis feature of the Team variants of VS2005+).
It generates a lot of noise (false positives), but does provide a lot of good practice.
Including: always use the overload that takes an IFormatProvider parameter if one is available - typically you will use CultureInfo.CurrentCulture for formatting output for the user, and CultureInfo.InvariantCulture for storing data in files, the registry etc.

Best way to parse float?

What is the best way to parse a float in CSharp?
I know about TryParse, but what I'm particularly wondering about is dots, commas etc.
I'm having problems with my website. On my dev server, the ',' is for decimals, the '.' for separator. On the prod server though, it is the other way round.
How can I best capture this?
I agree with leppie's reply; to put that in terms of code:
string s = "123,456.789";
float f = float.Parse(s, CultureInfo.InvariantCulture);
Depends where the input is coming from.
If your input comes from the user, you should use the CultureInfo the user/page is using (Thread.CurrentThread.CurrentUICulture).
You can get and indication of the culture of the user, by looking at the HttpRequest.UserLanguages property. (Not correct 100%, but I've found it a very good first guess) With that information, you can set the Thread.CurrentThread.CurrentUICulture at the start of the page.
If your input comes from an internal source, you can use the InvariantCulture to parse the string.
The Parse method is somewhat easier to use, if your input is from a controlled source. That is, you have already validated the string. Parse throws a (slow) exception if its fails.
If the input is uncontrolled, (from the user, or other Internet source) the TryParse looks better to me.
If you want persist values ( numbers, date, time, etc... ) for internal purpose. Everytime use "InvariantCulture" for formating & parsing values. "InvariantCulture" is same on every computer, every OS with any user's culture/language/etc...
string strFloat = (15.789f).ToString(System.Globalization.CultureInfo.InvariantInfo);
float numFloat = float.Parse(System.Globalization.CultureInfo.InvariantInfo, strFloat);
string strNow = DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantInfo);
DateTime now = DateTime.Parse(System.Globalization.CultureInfo.InvariantInfo, strNow);
You could always use the overload of Parse which includes the culture to use?
For instance:
double number = Double.Parse("42,22", new CultureInfo("nl-NL").NumberFormat); // dutch number formatting
If you have control over all your data, you should use "CultureInfo.InvariantCulture" in all of your code.
Use a neutral culture (or one you know) when parsing with Try/Parse.
Pass in a CultureInfo or NumberFormatInfo that represents the culture you want to parse the float as; this controls what characters are used for decimals, group separators, etc.
For example to ensure that the '.' character was treated as the decimal indicator you could pass in CultureInfo.InvariantCulture (this one is typically very useful in server applications where you tend to want things to be the same irrespective of the environment's culture).
Try to avoid float.Parse, use TryParse instead as it performs a lot better but does the same job.
this also applies to double, DateTime, etc...
(some types also offer TryParseExact which also performs even better!)
The source is an input from a website. I can't rely on it being valid. So I went with TryParse as mentioned before.
But I can't figure out how to give the currentCulture to it.
Also, this would give me the culture of the server it's currently running on, but since it's the world wide web, the user can be from anywhere...
you can know current Cuklture of your server with a simple statement:
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture;
Note that there id a CurrentUICulture property, but UICulture is used from ResourceMeanager form multilanguages applications. for number formatting, you must considere CurrentCulture.
I hope this will help you
One approach is to force localization to use dot instead of comma separator - this way your code will work identically on all windows machines independently from selected language and settings.
This approach is applicable to small gained applications, like test applications, console applications and so on. For application, which was localization in use this is not so useful, but depends on requirements of application.
var CurrentCultureInfo = new CultureInfo("en", false);
CurrentCultureInfo.NumberFormat.NumberDecimalSeparator = ".";
CurrentCultureInfo.NumberFormat.CurrencyDecimalSeparator = ".";
Thread.CurrentThread.CurrentUICulture = CurrentCultureInfo;
Thread.CurrentThread.CurrentCulture = CurrentCultureInfo;
CultureInfo.DefaultThreadCurrentCulture = CurrentCultureInfo;
This code forces to use dot ('.') instead of comma, needs to be placed at application startup.
Since you don't know the web user's culture, you can do some guesswork. TryParse with a culture that uses , for separators and . for decimal, AND TryParse with a culture that uses . for separators and , for decimal. If they both succeed but yield different answers then you'll have to ask the user which they intended. Otherwise you can proceed normally, given your two equal results or one usable result or no usable result.

Categories