Get current system setting's fraction separator - c#

In my app I parse a value from xml (string) to a double.
The value in the xml happens to have the dot as a fraction seperator whereas the system takes the current system settings and can have a different separator (dev system takes the comma for example).
Is there a way to tell double.TryParse() the dot is the fraction separator?
Should I manually replace the dot with the system's fraction separator? If so, how do I get this?

What you should do, in this situation, is use the XmlConvert class and its members to convert the value like it exists in the XML file to a regular variable. :)

Pass CultureInfo.InvariantCulture into double.TryParse:
double value;
bool success = double.TryParse(text, NumberStyles.Float,
CultureInfo.InvariantCulture,
out value);
(For genuinely standard XML formatting, Frederik's suggestion of using XmlConvert is the best idea though.)

Related

C# double.TryParse with InvariantCulture returns unexpected result

I'm trying to unit test a getprice method using NUnit. I am stuck with parsing the rawprice into double. My cultureinfo is en-US but I set it to de-DE for this test. Double parsing with numberstyles.any and invariantculture returns unexpected result.
The rawprice cultureinfo is unknown, it can be any. Also the server where it will run is also unknown and can be in any language.
For this test, I tried German for the rawprice and machine.
I tried parsing "9,42" but the result is 942.
[Test]
[SetCulture("de-DE")]
public void GetPrice_PriceTextWithCommaDecimal_ReturnsInvariantPrice()
{
var rawPriceText = "9,42";
double.TryParse(rawPriceText, NumberStyles.Any, CultureInfo.InvariantCulture, out double price);
//parsed price result is 942
...
}
It's not clear from your question what you expected. However, as far as what the code is doing, it's doing exactly what you told it to:
Providing NumberStyles.Any tells double.TryParse() to allow any format, except AllowHexSpecifier. This includes the AllowThousands option.
Providing the InvariantCulture causes parsing to use the ',' character as the thousands separator.
Parsing doesn't actually care where a thousands separator appears. I.e. it doesn't actually force the separator to be in the location where it would indicate a thousands-multiple digit.
So, when you ask it to parse "9,42", that text is interpreted using InvariantCulture (i.e. ignoring your current culture of de-DE), the ',' character is treated as a thousands separator (i.e. ignored for the purpose of computing the actual value), and you get the value 942, just like you asked for.
If you don't want that result, you need to use different arguments for the call to double.TryParse(). You would need to explain what you do want if you want advice on what arguments you should use. All we can say given the information currently in your question is what arguments you apparently don't want.
The cultures in ToString and TryParse must match.
It's either
var s = rawPrice.ToString(CultureInfo.InvariantCulture);
//rawPrice becomes 9.42
double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out double price);
or
CultureInfo.CurrentCulture = new CultureInfo("de-DE");
var s= rawPrice.ToString(CultureInfo.CurrentCulture);
//rawPrice becomes 9,42
double.TryParse(s, NumberStyles.Any, CultureInfo.CurrentCulture, out double price);
You should put your culture into the TryParse mechanism.
e.g.
double.TryParse(rawPriceText, NumberStyles.Any, new CultureInfo("de"), out double price);
For this case you could use CultureInfo.CurrentUICulture instead of creating a new CultureInfo.
You set the culture to de-DE.
But apparently you then decide to use the InvariantCulture instead, which will not recognize the , separator as decimal separator.
Using CurrentCulture instead will give you the expected result.

Formatting a String to be Converted to Double

I'm trying to convert a string to double. The incoming string is always going to be a whole number...no decimals. So, for example "90".
double percentToCheck = Convert.ToDouble(String.Format("{0:0.00}", SomeEntity.KeyIDs.SomePercentTrigger));
SomePercentTrigger is the % that I will be converting.
I get a "string is not in the correct format" error so how should I format this string? I've got to format it because if I don't I get the same error with just this during the conversion:
double percentToCheck = Convert.ToDouble(SomeEntity.KeyIDs.SomePercentTrigger);
UPDATED:
SomePercentTrigger is simply a string such as "80"..it'll always be a whole number too.
Update:
Your string is "52.0".
It must be the '.' that causes the FormatException.
You are probably on a machine where '.' is not set as the decimal point (e.g. I live in Germany and use German regional settings. Our decimal point is ',' )
To get around this problem you need to parse the string using CultureInfo.InvariantCulture.
var value = double.Parse(myString, CultureInfo.InvariantCulture);
InvariantCulture should be used for the parts of your application that revolve around data storage. Make sure you use it as well when converting doubles to strings Console.WriteLine(value.ToString(CultureInfo.InvariantCulture));
I suspect that SomeEntity.KeyIDs.SomePercentTrigger has some invalid characters in it (something other than digits, '.' and a optional leading '-'), say for example "80%"
So you're getting a FormatException on this line
double percentToCheck = Convert.ToDouble(String.Format("{0:0.00}", SomeEntity.KeyIDs.SomePercentTrigger));
because {0:0.00} formatting rules are only valid for numeric values.
Also you get the very same exception here:
double percentToCheck = Convert.ToDouble(SomeEntity.KeyIDs.SomePercentTrigger);
because "80%" can not be converted into a double.
You should either
put some logging right in front of the failing statement
or debug that code
and see what the actual content of SomeEntity.KeyIDs.SomePercentTrigger is.
Use double.Parse(string) or alternatively double.TryParse(string, out value)
It doesn't make sense to try to format a string. You would have to parse it to a number first in order to format it. Anyhow, there is no problem in parsing a number without decimals as a double, so the string is probably not containing what you think it does.
If the string contains a number in integer format, parse the string as an integer, and then convert the integer to a double:
double percentToCheck = (double)Int32.Parse(SomeEntity.KeyIDs.SomePercentTrigger);

C# format decimal to string

I need to format the Decimal variables Latitude=9113267; Longitude=59300357;
to string format 9,113267 and 59,300357
Thx
john
VascoP is right in how to convert the number to a "proper" decimal but he is wrong about how to convert those decimal values to a string. the ToString method has an overload whose signature is
public string ToString(IFormatProvider provider)
See: http://msdn.microsoft.com/en-us/library/3ebe5aks.aspx
You can use this to create a culture specific string. The examples on the linked page show how to do it but for completeness of answer an example might be:
(Latitude/1000000).ToString(CultureInfo.CreateSpecificCulture("en-GB") // Outputs with a "." decimal separator
(Latitude/1000000).ToString(CultureInfo.CreateSpecificCulture("de-DE") // Outputs with a "," decimal separator
I assume you have a specific culture that you want to be able to understand this so you should use the correct culture. That makes it much easier to change later if you want (eg you can pick up the culture from a global config setting) or have a user preference for the number format, etc.
Also if you start using custom formats (eg to put thousand separators in) then the cultureinfo object will again do the right thing.
It should also be noted at the end of all this that you may just need the .ToString if the default culture is actually the one you are using. You didn't provide that info though so I just assumed that a simple ToString wouldn't be doing the trick.
(Latitude/1000000).ToString().Replace('.', ',');
(Longitude/1000000).ToString().Replace('.', ',');
EDIT: Although this works, as stated by Chris, it is not best practice. You should use his solution instead.

Parse string to float number C#

I have float number in string. there is one problem. Number uses "." not "," as decimal point.
This code is not working:
MyNumber = float.Parse("123.5");
I know that I can use string replace function to "repair" this string before Parsing.
MyNumber = float.Parse("123.5".Replace('.',',');
But is there any other way to do it?
Using string replace is very fragile, and will lead to suttle bugs. Specify the IFormatProvider instead. For instance:
MyNumber = float.Parse("123.5", CultureInfo.InvariantCulture);
Or you can specify the NumberFormatInfo using another overload of Parse.
To add to Steven's question, rather than argue differently, the important thing is why the decimal separator is ..
If it's because the source is in a computer-readable format where the period decimal separator is specified as part of the document specification, then I'd go precisely as Steven does in using CultureInfo.InvariantCulture.
If it's human input in a particular locale, then you would want to match that locale by the CultureInfo appropriate for that locale, otherwise if the software is used with a different locale you'd have precisely the opposite problem. Generally you would want to set the thread's CurrentCulture to match this (CurrentCulture for formats, CurrentUICulture for languages). If you've done this, then you don't need to pass a culture at all, as the form float.Parse(string) uses that culture - however, you may wish to use float.Parse(string, CurrentCulture) to be explicit that this is what you are doing (and to shut up some software analysis that complains when you aren't specific in this way).
What gets really tricky, is if you potentially have to accept both period and comma - not least because many cultures that use period as a decimal separator, use comma as a thousands separator, and ultimately it's impossible to guarantee unambiguous parsing. However, assuming the thousands issue doesn't affect you, then the code you gave in your question is the approach, though I'd recommend doing the opposite (replace comma with period) and then parsing with the invariant culture, as that removes any further complications caused by yet more culture changes.
It depends on current culture of currently executed thread culture.
float.Parse("123,5", system.threading.thread.currentthread.currentculture);
float.Parse("123.5", system.threading.thread.currentthread.currentculture);
IF you strictly do not want culturespecific then
float.Parse("123.5", CultureInfo.InvariantCulture);

Why do I get a FormatException when converting a string to a float?

When I try to convert a string to float:
Console.WriteLine(float.Parse("6.59"));
it throws an exception:
Unhandled Exception: System.FormatException: Input string was not in a correct f
ormat.
at System.Number.ParseSingle(String value, NumberStyles options, NumberFormat
Info numfmt)
When I try it like this:
Console.WriteLine(Convert.ToSingle("6.59"));
It throws the same exception:
Unhandled Exception: System.FormatException: Input string was not in a correct f
ormat.
at System.Number.ParseSingle(String value, NumberStyles options, NumberFormat
Info numfmt)
at System.Convert.ToSingle(String value)
Can you explain why this happens?
The single argument Parse method uses the current culture to parse the string. If your current culture uses some other decimal separator, this will fail.
Try using the invariant culture:
float.Parse("6.59", CultureInfo.InvariantCulture)
The problem here is your culture.
Either set the invariant culture like this:
float.Parse("6.59", CultureInfo.InvariantCulture)
or use the correct decimal separator for your culture
float.Parse("6,59")
I wonder why you are using a literal string. If you are having problems entering literal floats, you can use
Console.WriteLine(6.59f)
If you do it this way culture doesn't matter because the value is decided at compile time.
You are probably using a culture that uses the , as a decimal seperator.
You could try to Parse using the InvariantCulture:
float.Parse("6.59", CultureInfo.InvariantCulture)
Culture - specific things. What's your default culture?
Some cultures use "," instead of ".". You can try this:
float.Parse("6.59", CultureInfo.InvariantCulture);
There could be problem with Locale/Culture. You need to set , instead of . for the decimal separator.
I know everyone here has already given the reason for the problem experienced but perhaps somebody should just expand on why Invariant fixes it.
The CultureInfo class is used either directly or indirectly by classes that format, parse, or manipulate culture-specific data, such as String, DateTime, DateTimeOffset, and the numeric types to deal with the differences in the way different cultures write these types.
In case of the decimal type some cultures use a period(.) whilst others use a comma (,). By default when you are using the Conversion Libraries it will make use of your local culture (that is the country your OS to configured for).
By specifying Invariant you say that you expect thousand separators to be commas(,) and decimal deliminator to be a period(.) as it is in most cultures.
A big problem that sometimes happens is that these cultural conventions change from the OS point of view. For example the South African (ZA) culture info used to behave like the invariant culture. Microsoft changed this with Windows 8 where the decimal suddenly became a comma and the thousand separator a space.This resulted in many legacy systems written in .Net suddently breaking when one migrated them to newer operating systems.
In the end, deal normalize all local culture info to invariant and persist and deal with them in your business logic in this format. Then localize it back on the front end. Same goes for DateTime, as soon as possible convert to UTC, and only back when you render an output.
You could also try Convert class to perform this task.
Convert.ToDecimal("6.59");

Categories

Resources