I'd like to make a program that isn't sensitive to the character , or . as input, in order to make some calculations without thinking about which symbol I should use to separate integer part from fractional part.
The only way i can imagine is to recognize the input string, check if there's a . and replace it with a , as my cultureType only accepts ,.
The problem is that I don't have any idea to make it, can someone help me?
if(inputString.Any(x => x == '.'))
{
inputString = inputString.Replace('.', ',');
}
I'm guessing (it's not in your question) that you're trying to parse a decimal, and the number may have a decimal separator and no thousand separator, and it might be a , and it might be a . A possible heuristic to guess which one it is, is to check the last occurrence of either.
That could be done by
string input = "123.456.496,58"; //or 123,456,789.58
int lastComma = input.LastIndexOf(",");
int lastPeriod = input.LastIndexOf('.');
NumberFormatInfo format = new NumberFormatInfo();
if (lastComma > lastPeriod) {
format.NumberDecimalSeparator = ',';
format.NumberGroupSeparator = '.';
} else {
format.NumberDecimalSeparator = '.';
format.NumberGroupSeparator = ',';
}
double parsed = Double.Parse(intput, format);
this fails when there is a group separator after the decimal separator, and other heurisics could be employed to change it (i.e. if there is only one non-numeric character, that one is the decimal separator. If there are multiple non-numeric special characters, and one of them only occurs once, that is the decimal separator)
In the end parsing a string with an unknown format will require some guesswork.
If you're not trying to parse numbers, but are doing something different entirely, disregard this answer, and pick one of the others.
if (yourString.Contains(".")) { youString = yourString.Replace(".", ","); }
Related
I want to display 0.12345 as "+12.3%". Format string "P1" or "p1" gives "12.3%". I have tried both "+P1" and "+p1" to no avail.
string sFoo = 0.12345.ToString("P1");
Update
I should have emphasized that I always want the proper sign, not "+". If the number is -0.12345, "P1" works exactly as I want: "-12.3%".
Not quite using P1, but same result:
0.12345.ToString("+#.#%;-#.#%");
If you prefer at least one leading digit (e.g. "+0.23%" instead of "+.23%"):
0.12345.ToString("+0.#%;-0.#%"));
Same for trailing digits (e.g. "+14.0%" instead of "+14%"):
0.12345.ToString("+0.0%;-0.0%"));
Reference: https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings#the--section-separator
var num = 0.12345;
var sign = num > 0 ? "+" : "";
var output = $"{sign}{num.ToString("P1")}";
I'm afraid there is no format string to display the positive sign. I've searched in NumberFormatInfo if some custom format could accept this, but with no avail.
You can however build some extension methods to fit your needs :
public static string ToSignedPercent(this double input)
{
return $"{(input >= 0 ? "+" : "")}{input.ToString("P1")}";
}
// ...
Console.WriteLine((0.12345).ToSignedPercent()); // +12.3%
Console.WriteLine((-0.6789).ToSignedPercent()); // -67.9%
Fiddle
Put the following in your main method. basically this approaches just sets the variable sFoo to have format of percentage with two decimals.
string sFoo = String.Format("Value: {0:P2}.", 0.12345); // formats as 12.35%
Console.WriteLine(sFoo);
I need to display a number with commas and a decimal point.
Eg:
Case 1 : Decimal number is 432324 (This does not have commas or decimal points).
Need to display it as: 432,324.00.
Not: 432,324
Case 2 : Decimal number is 2222222.22 (This does not have commas).
Need to display it as: 2,222,222.22
I tried ToString("#,##0.##"), but it is not formatting it correctly.
int number = 1234567890;
number.ToString("#,##0.00");
You will get the result 1,234,567,890.00.
Maybe you simply want the standard format string "N", as in
number.ToString("N")
It will use thousand separators, and a fixed number of fractional decimals. The symbol for thousands separators and the symbol for the decimal point depend on the format provider (typically CultureInfo) you use, as does the number of decimals (which will normally by 2, as you require).
If the format provider specifies a different number of decimals, and if you don't want to change the format provider, you can give the number of decimals after the N, as in .ToString("N2").
Edit: The sizes of the groups between the commas are governed by the
CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes
array, given that you don't specify a special format provider.
Try with
ToString("#,##0.00")
From MSDN
*The "0" custom format specifier serves as a zero-placeholder symbol. If the value that is being formatted has a digit in the position where the zero appears in the format string, that digit is copied to the result string; otherwise, a zero appears in the result string. The position of the leftmost zero before the decimal point and the rightmost zero after the decimal point determines the range of digits that are always present in the result string.
The "00" specifier causes the value to be rounded to the nearest digit preceding the decimal, where rounding away from zero is always used. For example, formatting 34.5 with "00" would result in the value 35.*
I had the same problem. I wanted to format numbers like the "General" format in spreadsheets, meaning show decimals if they're significant, but chop them off if not. In other words:
1234.56 => 1,234.56
1234 => 1,234
It needs to support a maximum number of places after the decimal, but don't put trailing zeros or dots if not required, and of course, it needs to be culture friendly. I never really figured out a clean way to do it using String.Format alone, but a combination of String.Format and Regex.Replace with some culture help from NumberFormatInfo.CurrentInfo did the job (LinqPad C# Program).
string FormatNumber<T>(T number, int maxDecimals = 4) {
return Regex.Replace(String.Format("{0:n" + maxDecimals + "}", number),
#"[" + System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + "]?0+$", "");
}
void Main(){
foreach (var test in new[] { 123, 1234, 1234.56, 123456.789, 1234.56789123 } )
Console.WriteLine(test + " = " + FormatNumber(test));
}
Produces:
123 = 123
1234 = 1,234
1234.56 = 1,234.56
123456.789 = 123,456.789
1234.56789123 = 1,234.5679
Try with
ToString("#,##0.###")
Produces:
1234.55678 => 1,234.556
1234 => 1,234
For Razor View:
$#string.Format("{0:#,0.00}",item.TotalAmount)
CultureInfo us = new CultureInfo("en-US");
TotalAmount.ToString("N", us)
Your question is not very clear but this should achieve what you are trying to do:
decimal numericValue = 3494309432324.00m;
string formatted = numericValue.ToString("#,##0.00");
Then formatted will contain: 3,494,309,432,324.00
All that is needed is "#,0.00", c# does the rest.
Num.ToString("#,0.00"")
The "#,0" formats the thousand separators
"0.00" forces two decimal points
If you are using string variables you can format the string directly using a : then specify the format (e.g. N0, P2, etc).
decimal Number = 2000.55512016465m;
$"{Number:N}" #Outputs 2,000.55512016465
You can also specify the number of decimal places to show by adding a number to the end like
$"{Number:N1}" #Outputs 2,000.5
$"{Number:N2}" #Outputs 2,000.55
$"{Number:N3}" #Outputs 2,000.555
$"{Number:N4}" #Outputs 2,000.5551
string Mynewcurrency = DisplayIndianCurrency("7743450.00");
private string DisplayIndianCurrency(string EXruppesformate)
{
string fare = EXruppesformate;
decimal parsed = decimal.Parse(fare, CultureInfo.InvariantCulture);
CultureInfo hindi = new CultureInfo("en-IN");
// string text = string.Format(hindi, "{0:c}", parsed);if you want <b>Rs 77,43,450.00</b>
string text = string.Format(hindi, "{0:N}", parsed); //if you want <b>77,43,450.00</b>
return ruppesformate = text;
}
For anyone looking at this now, and getting the "No overload for method 'ToString' takes 1 argument" when using:
TotalNumber.ToString("N")
My solution has been to use :
TotalNumber.Value.ToString("N")
I often get stuck on this when working directly inside an MVC View, the following wasn't working:
#Model.Sum(x => x.Number).ToString("N")
Whereas this works:
#Model.Sum(x => x.Number).Value.ToString("N")
Suppose I have a list of decimal numbers that I must format with a comma every three places, plus the appropriate number of digits after the decimal point. I want to use the .net string.Format method.
I want it to work like this:
string format = ???;
string s1 = string.Format(format, "1500"); // "1,500"
string s2 = string.Format(format, "1500.25"); // "1,500.25"
string s3 = string.Format(format. "3.1415926358979"); // "3.1415926358979"
I have seen other answers where the digits after the decimal are either limited to a fixed number of digits or truncated entirely, but this doesn't work for my application. I want to add the comma-separator to the whole part of the number, but keep the digits after the decimal exactly as they are.
First problem, you need to parse your strings before you can format them. There maybe some lose of precision. Then you need to decide what your maximum amount of precision you need is. Then you can do something like this:
string format = "{0:#,##0.#############}";
string s1 = string.Format(format, double.Parse("1500")); // "1,500"
string s2 = string.Format(format, double.Parse("1500.25")); // "1,500.25"
string s3 = string.Format(format, double.Parse("3.1415926358979")); // "3.1415926358979"
The # after the decimal place is a place holder for a decimal digit. If there are no more digits it won't show trailing zeros.
If being limited to a number of decimal places or possibly losing precision when converting to double. You could do something really cludgy like this:
public static string DecimalFormatCludge(string original)
{
var split = original.Split('.');
return string.Join(".", (new [] { int.Parse(split[0]).ToString("#,##0")}).Concat(split.Skip(1)));
}
This will split on the . in the string, parse the first part as an int, convert it back to a string correctly formatted and then just stick the decimal part back on (if there is one)
something like this?
string s1 = format.ToString("#,##0.00");
The format is something like this:
string format = "{0:#,##.##################}";
The problem:
Let's assume you are using a dot "." as a decimal separator in your regional setting and have coded a string with a comma.
string str = "2,5";
What happens when you decimal.TryParse(str, out somevariable); it?
somevariable will assume 0.
What can you do to solve it?
1-
You can
decimal.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out somevariable);
And it will return 25, and not 2.5 which is wrong.
2-
You can
decimal.TryParse(str.Replace(",","."), out num);
And it will return the proper value, BUT, if the user uses "," as a decimal separator it will not work.
Possible solution that I can't make it work:
Get the user decimal separator in regional settings:
char sepdec = Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
And make somehow the replace from ",",sepdec , that way it would stay a comma if its a comma, and replace by an actual dot if the user uses dots.
Hints?
Edit: Many users posted useful information, lately, using the arguments NumberStyles.Any, CultureInfo.GetCultureInfo("pt-PT") on a tryParse wouldn't work if your separator is set to "," So it pretty much doesnt fullfill the premise of making a tryparse "universal".
I'll work around this, if anyone has more hints you'r welcome
I know the thread is a little bit older, but I try to provide an answer.
I use regular expression to determine the used number format in the string.
The regex also matches numbers without decimal separators ("12345").
var numberString = "1,234.56"; // en
// var numberString = "1.234,56"; // de
var cultureInfo = CultureInfo.InvariantCulture;
// if the first regex matches, the number string is in us culture
if (Regex.IsMatch(numberString, #"^(:?[\d,]+\.)*\d+$"))
{
cultureInfo = new CultureInfo("en-US");
}
// if the second regex matches, the number string is in de culture
else if (Regex.IsMatch(numberString, #"^(:?[\d.]+,)*\d+$"))
{
cultureInfo = new CultureInfo("de-DE");
}
NumberStyles styles = NumberStyles.Number;
bool isDouble = double.TryParse(numberString, styles, cultureInfo, out number);
HTH
Thomas
I just want to say that HTH Thomas solution worked really well in my project, except for when trying to parse negative decimal numbers with commas. One solution to this, which is probably not optimized because I don't fully understand the regex Ismatch code, but that works is adding the possibility of finding a "-" before the number in the ifs statements, like this:
var cultureInfo = CultureInfo.InvariantCulture;
if (Regex.IsMatch(equation.inputFieldsTexts[i], #"^(:?[\d,]+\.)*\d+$") || Regex.IsMatch(equation.inputFieldsTexts[i], #"^(:?[-\d,]+\.)*\d+$"))
{
cultureInfo = new CultureInfo("en-US");
}
// if the second regex matches, the number string is in DE culture
if (Regex.IsMatch(equation.inputFieldsTexts[i], #"^(:?[\d.]+,)*\d+$") || Regex.IsMatch(equation.inputFieldsTexts[i], #"^(:?[-\d.]+,)*\d+$"))
{
cultureInfo = new CultureInfo("de-DE");
}
The solution I use is to simply show the user what the parsed value is.
I have a custom TextBox control which verifies the input when the control loses focus and such. If the control expects a floating point value (which is a property), then it will try to parse the value entered. If the TryParse succeeds, I display the out value in the control's text.
This way, when a user enters 12.3 the value might change to 123 because in the current culture 12,3 is expected. It's then up to them to decide to correct this.
How about this method:
clean the string from anything else than numbers, dot, comma and negative sign
take the last index of dot or comma
split the clean string and remove all thousands separators from the first part
convert both parts to integer
change the sign of the second part if necessary
add the first part with the second part divided by decimal places
public static bool TryParseDoubleUniversal(this string s, out double result) {
result = 0.0;
if (string.IsNullOrEmpty(s)) return false;
var clean = new string(s.Where(x => char.IsDigit(x) || x == '.' || x == ',' || x == '-').ToArray());
var iOfSep = clean.LastIndexOfAny(new[] { ',', '.' });
var partA = clean.Substring(0, iOfSep).Replace(",", string.Empty).Replace(".", string.Empty);
var partB = clean.Substring(iOfSep + 1);
if (!int.TryParse(partA, out var intA)) return false;
if (!int.TryParse(partB, out var intB)) return false;
if (intA < 0) intB *= -1;
var dp = double.Parse("1".PadRight(partB.Length + 1, '0'));
result = intA + intB / dp;
return true;
}
The question is old but since it was my first hit on Google. And the approach in How to change symbol for decimal point in double.ToString()? seems to be a valid solution you can use the NumberFormatInfo to set the decimal separator like this:
string value = "3,2";
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalSeparator = ",";
decimal.TryParse(value, NumberStyles.Any, nfi, out decimal dec);
I found a solution, I'm a beginner on this regional and comma-dots theme so if you have comments to improve the understanding of this please be welcome.
We start of by getting what decimal separator the user has set in his regional options outside before the Form{InitializeComponent();} (I want a universal variable that will allow me to correct the code)
char sepdec = Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
In the tryParse, to get it to behave universally we will read the dots and commas in the string, and turn them into the decimal separator we defined as sepdec
decimal.TryParse(str.Replace(",",sepdec.ToString()).Replace(".",sepdec.ToString()), out somevariable);
I hope this helps, please comment improvement suggestions!
In Android Xamarin, I ran into the same issue several times. Some solutions worked until the Android got upgraded into a new version, then the problem came out again. So I came with an universal solution, which works fine. I read the numeric input as text, then parse it into decimal with a custom parser.
The custom parser is returning 0 when parsing into decimal is not possible. It does allow input text containing decimal number with either comma or dot, with no group separators:
public static decimal ParseTextToDecimal(string decimalText)
{
if (decimalText == String.Empty) return 0;
string temp = decimalText.Replace(',', '.');
var decText = temp.Split('.');
if (!Int32.TryParse(decText[0], out int integerPart)) return 0;
if (decText.Length == 1) return integerPart;
if (decText.Length == 2)
{
if (!Int32.TryParse(decText[1], out int decimalPart)) return 0;
decimal powerOfTen = 10m;
for (int i = 1; i < decText[1].Length; i++) powerOfTen *= 10;
return integerPart + decimalPart / powerOfTen;
}
return 0; // there were two or more decimal separators, which is a clear invalid input
}
I want to parse a string from an Text input to decimal. The value represents a currency value.
Currently i got this solution:
private Decimal CastToDecimal(string value)
{
Decimal result;
var valid = Decimal.TryParse(value, NumberStyles.Currency, null, out result);
return valid ? result : -1;
}
This works pretty well so far, except for possible culture-differences. I'm german and i expect most users to enter german-style puctuation. But it is possible that someone uses "." instead of "," and the conversion will fail.
"123,45€" => 123.45
"123.456,78€" => 123456.78
"123.45€" => 12345 <- I want the result to be 123.45 here
Is there a way to automatically detect the used culture for a decimal value? Such that it does not matter if you use german or english punctuation, you still get the same result?
Update:
Thanks to your help, i created a method which does what i want (i think).
private static Decimal CastToDecimal(string value)
{
Decimal resultDe;
Decimal resultEn;
var style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands;
var cultureDe = CultureInfo.CreateSpecificCulture("de-DE");
var cultureEn = CultureInfo.CreateSpecificCulture("en-GB");
var deValid = Decimal.TryParse(value, style, cultureDe, out resultDe);
var enValid = Decimal.TryParse(value, style, cultureEn, out resultEn);
var minVal = Math.Min(resultDe, resultEn);
var maxVal = Math.Max(resultDe, resultEn);
if (!deValid)
return resultEn;
if (!enValid)
return resultDe;
return BitConverter.GetBytes(decimal.GetBits(minVal)[3])[2] > 2 ? maxVal : minVal;
}
This code...
Console.WriteLine(CastToDecimal("123,45"));
Console.WriteLine(CastToDecimal("123.45"));
Console.WriteLine(CastToDecimal("123,450"));
Console.WriteLine(CastToDecimal("123.450"));
Console.WriteLine(CastToDecimal("123.123,45"));
Console.WriteLine(CastToDecimal("123,123.45"));
returns this:
123,45
123,45
123450
123450
123123,45
123123,45
the solution at http://msdn.microsoft.com/en-us/library/3s27fasw%28v=vs.110%29.aspx
which includes setting the NumberStyle may be helpful.
...
value = "1.345,978";
style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands;
culture = CultureInfo.CreateSpecificCulture("es-ES");
if (Double.TryParse(value, style, culture, out number))
Console.WriteLine("Converted '{0}' to {1}.", value, number);
else
Console.WriteLine("Unable to convert '{0}'.", value);
// Displays:
// Converted '1.345,978' to 1345.978.
value = "1 345,978";
if (Double.TryParse(value, style, culture, out number))
Console.WriteLine("Converted '{0}' to {1}.", value, number);
else
Console.WriteLine("Unable to convert '{0}'.", value);
...
I encountered the same problem some time ago. My solution was writing my own parser in Java. The algorithm first cleans up the string. Brief description follows:
Scan string from left to right
If char = '.' then dotFound=true ; lastSeparatorPosition = index ; dots++
If char = ',' then commaFound=true ; lastSeparatorPosition = index ; commas++
If dots == 0 && commas == 0 then its an integer => done
If dots > 0 && commas > 0 then the one at lastSeparatorPosition is the decimal separator. Remove the others from the string => done
/* only one separator type */ if ( dots + commas ) > 1 then remove them // because must be thousands separator => done
/* separator occurs once */ if numberOfDigits right of separator == 3 then you have to decide :-) either integer or decimal with 3 digits in fraction
7 is the only remaining problem like chiastic-security already stated. Here you can only decide taken the conceptual environment into account. All other cases are safe.
Have fun
This can't be done, simply because there are strings that are meaningful in two different cultures, but mean different things. For instance:
123.456
123,456
The first is a bit over 123 in the UK, but 123456 in Germany; the second is 123456 in the UK but a bit over 123 in France.
The only solution is to add validation on input and give user and example by the way if it is a webpage then find a way to get input according to user's culture. I suggests you to not to try to do what you are trying because there are some culture which contradict each others for example in currency;
US/Australia/Many others uses following format
45,999.95
where , is thousand separator and . is decimal separator
whereas in some European countries
45.999,95
means the same as above but thousands separator is . and , is used as decimal separator.
Now issue is there is no guarantee that user use both separator and your system may assume thousand separator as decimal and so on.
If you really don't want to bother user then make separate input fields for major and minor currencies.
So its better to not to go there. I believe this may help. Happy Coding :)
Update:
Same case is with date format e.g. in US format month comes first and then day whereas in Australia day comes first and then month now 02/01/2015 input will mean differently system can't tell the intention of user.