I can't figure out how to do the following :
I want to import some data from a file, including numeric values. The user can personalize separators, which are char. For exemple, a number may look like this : 2 524,2. Here, we have a "thousands" separator () and a "decimal" separator (,).
I try to convert these strings as double.
I know that I may do something like this :
double.Parse(str.Replace(tSep, '\0').Replace(dSep, '.'));
But I'm looking for a potential way of doing it more properly.
Thank you in advance.
Try this:
string s = "2 524,2";
CultureInfo ci = new CultureInfo(1);
NumberFormatInfo ni = new NumberFormatInfo();
ni.NumberGroupSeparator = " ";
ni.NumberDecimalSeparator = ",";
ci.NumberFormat = ni;
decimal d = decimal.Parse(s, ci);
double.Parse(str.Replace(' ', '\0').Replace(',', '.'));
is fine, but you should also set the culture to InvariantCulture
double.Parse(str.Replace(' ', '\0').Replace(',', '.',
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture));
in order to be sure that your code will work on every user culture setting
Related
I have two nvarchar fields in a database to store the DataType and DefaultValue, and I have a DataType Double and value as 65.89875 in English format.
Now I want the user to see the value as per the selected browser language format (65.89875 in English should be displayed as 65,89875 in German). Now if the user edits from German format to 65,89875 which is 65.89875 equivalent in English, and the other user views from an English browser it comes as 6589875.
This happens because in the database it was stored as 65,89875 in the nvarchar column and when converted using English culture it becomes 6589875 since it considers , as a separator which is a decimal operator for German.
How do I get this working for all the browsers?
You need to define a single locale that you will use for the data stored in the database, the invariant culture is there for exactly this purpose.
When you display convert to the native type and then format for the user's culture.
E.g. to display:
string fromDb = "123.56";
string display = double.Parse(fromDb, CultureInfo.InvariantCulture).ToString(userCulture);
to store:
string fromUser = "132,56";
double value;
// Probably want to use a more specific NumberStyles selection here.
if (!double.TryParse(fromUser, NumberStyles.Any, userCulture, out value)) {
// Error...
}
string forDB = value.ToString(CultureInfo.InvariantCulture);
PS. It, almost, goes without saying that using a column with a datatype that matches the data would be even better (but sometimes legacy applies).
You can change your UI culture to anything you want, but you should change the number separator like this:
CultureInfo info = new CultureInfo("fa-IR");
info.NumberFormat.NumberDecimalSeparator = ".";
Thread.CurrentThread.CurrentCulture = info;
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
With this, your strings converts like this: "12.49" instead of "12,49" or "12/49"
Convert.ToDouble(x) can also have a second parameter that indicates the CultureInfo and when you set it to
System.Globalization.CultureInfo InvariantCulture
the result will allways be the same.
I took some help from MSDN, but this is my answer:
double number;
string localStringNumber;
string doubleNumericValueasString = "65.89875";
System.Globalization.NumberStyles style = System.Globalization.NumberStyles.AllowDecimalPoint;
if (double.TryParse(doubleNumericValueasString, style, System.Globalization.CultureInfo.InvariantCulture, out number))
Console.WriteLine("Converted '{0}' to {1}.", doubleNumericValueasString, number);
else
Console.WriteLine("Unable to convert '{0}'.", doubleNumericValueasString);
localStringNumber =number.ToString(System.Globalization.CultureInfo.CreateSpecificCulture("de-DE"));
You can convert the value user provides to a double and store it again as nvarchar, with the aid of FormatProviders. CultureInfo is a typical FormatProvider. Assuming you know the culture you are operating,
System.Globalization.CultureInfo EnglishCulture = new System.Globalization.CultureInfo("en-EN");
System.Globalization.CultureInfo GermanCulture = new System.Globalization.CultureInfo("de-de");
will suffice to do the neccesary transformation, like;
double val;
if(double.TryParse("65,89875", System.Globalization.NumberStyles.Float, GermanCulture, out val))
{
string valInGermanFormat = val.ToString(GermanCulture);
string valInEnglishFormat = val.ToString(EnglishCulture);
}
if(double.TryParse("65.89875", System.Globalization.NumberStyles.Float, EnglishCulture, out val))
{
string valInGermanFormat = val.ToString(GermanCulture);
string valInEnglishFormat = val.ToString(EnglishCulture);
}
Use InvariantCulture. The decimal separator is always "." eventually you can replace "," by "."
When you display the result , use your local culture. But internally use always invariant culture
TryParse does not allway work as we would expect There are change request in .net in this area:
https://github.com/dotnet/runtime/issues/25868
I have this function in my toolbelt since years ago (all the function and variable names are messy and mixing Spanish and English, sorry for that).
It lets the user use , and . to separate the decimals and will try to do the best if both symbols are used.
Public Shared Function TryCDec(ByVal texto As String, Optional ByVal DefaultValue As Decimal = 0) As Decimal
If String.IsNullOrEmpty(texto) Then
Return DefaultValue
End If
Dim CurAsTexto As String = texto.Trim.Replace("$", "").Replace(" ", "")
''// You can probably use a more modern way to find out the
''// System current locale, this function was done long time ago
Dim SepDecimal As String, SepMiles As String
If CDbl("3,24") = 324 Then
SepDecimal = "."
SepMiles = ","
Else
SepDecimal = ","
SepMiles = "."
End If
If InStr(CurAsTexto, SepDecimal) > 0 Then
If InStr(CurAsTexto, SepMiles) > 0 Then
''//both symbols was used find out what was correct
If InStr(CurAsTexto, SepDecimal) > InStr(CurAsTexto, SepMiles) Then
''// The usage was correct, but get rid of thousand separator
CurAsTexto = Replace(CurAsTexto, SepMiles, "")
Else
''// The usage was incorrect, but get rid of decimal separator and then replace it
CurAsTexto = Replace(CurAsTexto, SepDecimal, "")
CurAsTexto = Replace(CurAsTexto, SepMiles, SepDecimal)
End If
End If
Else
CurAsTexto = Replace(CurAsTexto, SepMiles, SepDecimal)
End If
''// At last we try to tryParse, just in case
Dim retval As Decimal = DefaultValue
Decimal.TryParse(CurAsTexto, retval)
Return retval
End Function
I get from a webservice the following strings:
12.95
or
1,200.99
Is there an option to convert these values to the following values without manipulating the string?
12,95
or
1200,99
I tried it with some Culture options but didn't get it right...
EDIT
I tried this:
//return string.Format( "{0:f2}", Convert.ToDecimal( price ) );
//return string.Format(CultureInfo.GetCultureInfo("de-de"), "{0:0}", price);
NumberFormatInfo format = new System.Globalization.NumberFormatInfo();
format.CurrencyDecimalDigits = 2;
format.CurrencyDecimalSeparator = ",";
format.CurrencyGroupSeparator = "";
return decimal.Parse(price).ToString(format);
var input = "1,200.99";
//Convert to decimal using US culture (or other culture using . as decimal separator)
decimal value = decimal.Parse(input, CultureInfo.GetCultureInfo("en-US"));
//Convert to string using DE culture (or other culture using , as decimal separator)
string output = value.ToString(CultureInfo.GetCultureInfo("de-DE"));
Console.WriteLine(output); //1200,99
What about something like this:
double number;
double.TryParse("1,200.99", NumberStyles.Any, CultureInfo.CreateSpecificCulture("en-US"), out number);
var formattedNumber = number.ToString(CultureInfo.CreateSpecificCulture("de-DE"));
Then return or write out formattedNumber (whatever you need to do).
Yes and no. First, what you have is a string, and so you cannot change the formatting of it as you're attempting to. However, to achieve what you would like, you can parse the string into a decimal value and then use the formatting options for decimals to display it in any reasonable way.
You may try for something like this:
String.Format("{0:#,###0}", 0);
or may be like this:
string str = yourNumber.Remove(",").Replace(".",",");
Close enough tronc,
Try this snippet:
String curStr = "12.95";
Decimal decVal;
var valid = Decimal.TryParse(curStr, out decVal);
if (!valid) throw new Exception("Invalid format.");
String newFormat = decVal.ToString("C", System.Globalization.CultureInfo.CreateSpecificCulture("de-DE"));
Within the toString(...) call, you can append a number after 'C' to specify how many decimal places should follow. E.g "C3".
I'm having issues with currency formatting in C#.
I'm using framework 2.0.
When I use this code:
CultureInfo culture = new CultureInfo("fr-FR", false);
NumberFormatInfo numberFormatInfo = (NumberFormatInfo)culture.NumberFormat.Clone();
numberFormatInfo.CurrencySymbol = "CHF";
price.Value.ToString("C", numberFormatInfo) seems to give me a string with a white space between amount and currency. That's horrible! I absolutely need a no-break space!
What is going on? Am I missing a format property or is it the C# standard?
Thanks for your help!
So basically you want price.Value.ToString("C", numberFormatInfo).Replace(' ', '\u00A0');? At least that should be the code for non breaking space. – Corak
Exactly the same as above commentor, but using the asci-values instead; > price.Value.ToString("C", numberFormatInfo).Replace((char) 32, (char) 160); (160 is a lot > easier to remember, atleast for me :)) – flindeberg
Adding an answer based on my interpretation of the question, which #Corak seems to share.
// Convert "breaking" spaces into "non-breaking" spaces (ie the html )
price.Value.ToString("C", numberFormatInfo).Replace((char) 32, (char) 160);
Doing the same with unicode (courtesy of #Corak's link):
// Convert "breaking" spaces into "non-breaking" spaces without int cast to char
price.Value.ToString("C", numberFormatInfo).Replace(' ', '\u00A0');
And btw (roslyn repl):
> '\u00A0' == (char) 160
true
And if you are going to be using it alot also get the extension method:
public static class StringExtensions
{// CurrencyType is your currency type, guessing double or decimal?
public static string ToCurrencyString(this CurrencyType value, IFormatInfo format)
{
return value.ToString("C", format).Replace((char) 32, (char) 160);
}
}
Use:
numberFormatInfo.CurrencyPositivePattern = 1;
For value 1 the format is n$ where $ is currency symbol and in your case its CHF
Formatting Types - MSDN
The CurrencyNegativePattern or CurrencyPositivePattern property, which
returns an integer that determines the following:
The placement of the currency symbol.
Whether negative values are indicated by a leading negative sign, a trailing negative sign, or parentheses.
Whether a space appears between the numeric value and the currency symbol.
Try the following code:
CultureInfo culture = new CultureInfo("fr-FR", false);
NumberFormatInfo numberFormatInfo = (NumberFormatInfo)culture.NumberFormat.Clone();
numberFormatInfo.CurrencySymbol = "CHF";
numberFormatInfo.CurrencyPositivePattern = 1;
decimal d = 123.23M;
var temp = d.ToString("C", numberFormatInfo);
Output:
123,23CHF
You can replace it.
price.ToString("C", numberFormatInfo).Replace(" ", "")
or better set NumberFormatInfo.CurrencyPositivePattern to 1
numberFormatInfo.CurrencySymbol = "CHF";
numberFormatInfo.CurrencyPositivePattern = 1;
Full example;
CultureInfo culture = new CultureInfo("fr-FR", false);
NumberFormatInfo numberFormatInfo = (NumberFormatInfo)culture.NumberFormat.Clone();
numberFormatInfo.CurrencySymbol = "CHF";
numberFormatInfo.CurrencyPositivePattern = 1;
Console.WriteLine((1.5M).ToString("C", numberFormatInfo));
Output will be;
1,50CHF
Here a DEMO.
From Formatting Types
The CurrencyNegativePattern or CurrencyPositivePattern property, which
returns an integer that determines the following:
The placement of the currency symbol.
Whether negative values are indicated by a leading negative sign, a trailing negative sign, or parentheses.
Whether a space appears between the numeric value and the currency symbol.
You can configure the CurrencyPositivePattern and set it to something appropriate.
// whatever code you had
NumberFormatInfo numberFormatInfo = (NumberFormatInfo)culture.NumberFormat.Clone();
numberFormatInfo.CurrencyPositivePattern = 1; // will format like 25.00CHF
Seems like by default it includes space when it comes to other currencies than $
double value = 12345.6789;
Console.WriteLine(value.ToString("C", CultureInfo.CurrentCulture));
Console.WriteLine(value.ToString("C3", CultureInfo.CurrentCulture));
Console.WriteLine(value.ToString("C3",
CultureInfo.CreateSpecificCulture("da-DK")));
// The example displays the following output on a system whose
// current culture is English (United States):
// $12,345.68
// $12,345.679
// kr 12.345,679
if you want to replace space, you can use as Soner said,
numberString.ToString("C", numberFormatInfo).Replace(" ", "");
In your global.asax ou can globaly change the culture and chose to remove the space like this :
CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture("fr-FR"); //Get you own culture
cultureInfo.NumberFormat.CurrencyPositivePattern = 1; //To remove the space
Thread.CurrentThread.CurrentUICulture = cultureInfo; //Apply globaly to your application
Thread.CurrentThread.CurrentCulture = cultureInfo; //Apply globaly to your application
The clean solution is set your CurrencyPositivePattern to 0.
Example:
CultureInfo _culture= (CultureInfo) culture.Clone();
_culture.NumberFormat.CurrencyPositivePattern = 0;
var stringFormat = number.ToString("c3", _culture);
input: 1234567.845
output: $1.234.568
output: €1.234.568
output: S/1.234.568
I have int variables, example:
int money = 1234567890;
How I can insert "." into money, and make its format like this:
1.234.567.890
You can simply do this:
var text = money.ToString("N0",
System.Globalization.CultureInfo.GetCultureInfo("de"));
The result is:
1.234.567.890
(I just picked the German culture as I knew they use . for the separator.)
You can use NumberFormatInfo.NumberGroupSeparator:
NumberFormatInfo nfi = new CultureInfo( "en-US", false ).NumberFormat;
nfi.NumberGroupSeparator = ".";
Int64 myInt = 1234567890;
Console.WriteLine( myInt.ToString( "N", nfi ) );
(Link to ideone.)
To get exactly the format, use
int money = 1234567890;
money.ToString(#"#\.###\.###\.##0");
More information on custom formats here. You need to escape the dot because otherwise the first one will be interpreted as the decimal one. 0 in the end is necessary if you want to display it for zero values.
If you want a "Money' format try:
int money = 1234567890;
string moneyString = String.Format("{0:C}", money);
returns "$1,234,567,890.00"
Im not sure what money format uses '.' instead of ',' but that could just be a globalization thing.
I am working on a C# application. I want to change number decimal figure with comma(,) where i have dot(.) using regular expression.
For example:
Price= 100,00.56
As this international rule of representing numeric values but I Sweden they have different ways for numbers Like
Price= 100.00,56
So i want to change dot(.) into comma(,) and comma(,) into dot(.) using RegEx. Could guide me about this.
When formatting numbers, you should use the string format overload that takes a CultureInfo object. The culture name for swedish is "sv-SE", as can be seen here.
decimal value = -16325.62m;
Console.WriteLine(value.ToString(CultureInfo.CreateSpecificCulture("sv-SE")));
Edit:
As #OregonGhost points out - parsing out numbers should also be done with CultureInfo.
Not a RegEx solution but from my experience - more correct:
public static string CheckDecimalDigitsDelimiter(this string instance)
{
var sv = new CultureInfo("sv-SE");
var en = new CultureInfo("en-US");
decimal d;
return (!Decimal.TryParse(instance, NumberStyles.Currency, sv, out d) &&
Decimal.TryParse(instance, NumberStyles.Currency, en, out d)) ?
d.ToString(sv) : // didn't passed by SV but did by EN
instance;
}
What does this method do? It ensures that if given string is incorrect Sweden string but is correct English - convert it to Sweden, e.g. 100,00 -> 100,00 but 100.00 -> 100,00.
You can do this even without regex. For example
var temp = price.Replace(".", "<TEMP>");
var temp2 = temp.Replace(",", ".");
var replaced = temp2.Replace("<TEMP>", ",");
Also have a look at
System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator
Not sure what 100,00.56 represents, did you mean 10.000,56?
To answer your question:
For such a simple task, why use RegEx? You can do it much easier:
string oldValue = "100,00.56";
char dummyChar = '&'; //here put a char that you know won't appear in the strings
var newValue = oldValue.Replace('.', dummyChar)
.Replace(',', '.')
.Replace(dummyChar, ',');
Edit
I agree with #Oded, for formatting numbers use the CultureInfo class.
Do not rely on RegExp for this kind of thing :) Use the build in cultures fx:
decimal s = decimal.Parse("10,000.56", NumberStyles.Currency, CultureInfo.GetCultureInfo("en-US"));
string output = s.ToString("N",CultureInfo.GetCultureInfo("da-DK"));
en-US will parse it correctly and da-DK uses the other kind of representation. I live in DK and therefore use that but you should use the culture which fits your output.