C# format float to string with separators and padding 0 - c#

I need to format ints and floats to string.
If it's float, I need , to be decimal separator. And . must be thousand separator.
Also, I need to complete remaining decimals with 0. Some examples:
float:
45,3: 000.045,30
125: 000.125,00
83560.195: 083.560,19
int:
45: 000.045
5789: 005.789
I managed to format thousands with "{0:#,0}" but I still can't find how to format decimals and how to properly pad keeping separators.
This must be done regardless of configured culture :/

This works with the given examples:
NumberFormatInfo numberFormat = new NumberFormatInfo
{
NumberDecimalSeparator=",",
NumberGroupSeparator="."
};
string formatFloat(float f)
{
return f.ToString("0####,0.00",numberFormat);
}
string formatInt(int i)
{
return i.ToString("0####,0",numberFormat);
}

You can set the culture to a European culture, and format:
string.Format(new CultureInfo("de-DE"), "{0:000,000.00}", num).Dump();

Related

Converting a number from a string to an int with decimals separated by comma or dot

I have a string which contains a number. It can be one with decimals, followed by either a comma or a dot, depending on the user's locale.
The numbers are actually hundredths and I want to convert them to plain old ints. For example, I want strings "14.5" and "14,5000" to end up as int 1450.
It's probably me, but I can't figure out how to correctly convert this number into an int with a corresponding value when the decimals are separated by a comma. I've tried this:
double valueDouble;
double.TryParse(SpecificTemperatureTextBox.Text, NumberStyles.Any,
CultureInfo.CurrentCulture, out valueDouble);
int valueInt = Convert.ToInt32(valueDouble * 100);
But this comes out wrong sometimes. Here are my results:
TextBox value Expected result Converted result
"14" 1400 1400 (good)
"14.0" 1400 1400 (good)
"14.5" 1450 1450 (good)
"14,0" 1400 14000
"14,5" 1450 14500
Am I not using the System.Globalization correctly when I'm converting? I don't want to replace , with . in the string, because that seems too dirty.
How can I do this?
Maybe safest bet would be to try parse input with both cultures, something like this:
private static int ConvertStringValue(string value)
{
decimal valDouble;
var comma = (NumberFormatInfo)CultureInfo.InstalledUICulture.NumberFormat.Clone();
comma.NumberDecimalSeparator = ",";
comma.NumberGroupSeparator = ".";
var dot = (NumberFormatInfo)CultureInfo.InstalledUICulture.NumberFormat.Clone();
dot.NumberDecimalSeparator = ".";
dot.NumberGroupSeparator = ".";
if (decimal.TryParse(value, NumberStyles.Currency, comma, out valDouble))
{
return Convert.ToInt32(valDouble * 100);
}
else if (decimal.TryParse(value, NumberStyles.Currency, dot, out valDouble))
{
return Convert.ToInt32(valDouble * 100);
}
else
{
return Convert.ToInt32(value);
}
}
Using CurrentCulture will correctly parse numbers with either dot or comma depending on the value of CurrentCulture. But not both simultaneously as in no culture dot and comma are interchangeable.
So, you will have to replace either all commas for dots or vice versa. Then parse with the 'dot separator culture' or 'comma separator culture' setting.

.NET General Number Formatting with Thousands Separator

Is it possible in .NET to have the most compact number formatting like "G"eneral Number formatting, with extra thousands separator.
I can't use the following
String.Format("{0:#,###.###}",32445.324777M)
Because I get "32,445.325", and instead the result I want should be "32.445,325777". Is should also work with an arbitrary number of significant digits in the fractional part.
PS: I only need this for decimals.
That's where formatting culture comes in. You need to get a format specifier that matches your requirements. The default you have is usually the current culture, UI culture or invariant culture. The results you're getting imply you're using the US culture.
If you have a specific culture you want to output the number in, use that. If not, you can create your own:
var nfi =
new NumberFormatInfo
{
NumberDecimalSeparator = ",",
NumberGroupSeparator = "."
};
var ci =
new CultureInfo(CultureInfo.InvariantCulture.LCID) { NumberFormat = nfi };
return string.Format(ci, "{0:#,###.########}", 32445.324777M)
If you want to also get the most compact number, you'll have to use your own code. The easiest way would be to try both, and return the smaller resulting string.
If you want to, you can still use the string.Format syntax too - you can code your own ICustomFormatter to handle that:
void Main()
{
var number = 32445.324777M;
string.Format(new MyNumberFormatter(), "{0:MyG}", number).Dump();
}
class MyNumberFormatter : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type type)
{
return this;
}
public string Format(string fmt, object arg, IFormatProvider formatProvider)
{
if (fmt != "MyG" || !(arg is decimal)) return string.Format(CultureInfo.CurrentCulture, "{0:" + fmt + "}", arg);
return "Hi";
}
}
This implementation is somewhat hacky, of course, I'm sure you can find better examples. But it does work. In the Format method, you can choose the format that fits better for the given number, or even just try something like doing the usual ToString("G", CultureInfo.InvariantCulture) and adding the decimal separators to that string. Whatever floats your boat :)
From the .NET documentation
The "#" custom format specifier serves as a digit-placeholder symbol.
If the value that is being formatted has a digit in the position where
the "#" symbol appears in the format string, that digit is copied to
the result string.
Otherwise, nothing is stored in that position in
the result string. Note that this specifier never displays a zero that
is not a significant digit, even if zero is the only digit in the
string. It will display zero only if it is a significant digit in the
number that is being displayed.
The "##" format string 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 "##" would result in the value 35.
It's not possible to format an unspecified amount of decimal places with the default formatting possibilities. So you should consider writing your own implementation if needed.
Also about the decimal and thousands separator, it depends upon your system settings, but you can override them by using a different culture as #Luaan described it in his answer.
You should also probably look into this answer.
If you want full control create yoru own formatter lik below. See case "U" for your format.
public class CustomerFormatter : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}
public string Format(string format,
object arg,
IFormatProvider formatProvider)
{
if (!this.Equals(formatProvider))
{
return null;
}
else
{
// generic formatter if no formater specified
if (String.IsNullOrEmpty(format))
format = "G";
// not a decimal type object
if (!(arg is decimal))
return null;
// get value
decimal val = (decimal)arg;
// convert value into generic culture string for control of format
string valueString = val.ToString();
// get string in required format type
format = format.ToUpper();
switch (format)
{
// our user format
case "U":
// get decimals
string decimals = val.ToString("G", CultureInfo.InvariantCulture);
decimals = decimals.Substring(decimals.IndexOf('.') + 1);
// get current culture info
NumberFormatInfo nfi = new CultureInfo(CultureInfo.CurrentCulture.Name).NumberFormat;
// set our separators
nfi.NumberGroupSeparator = ",";
nfi.NumberDecimalSeparator = ".";
// set numebr of decimals
nfi.NumberDecimalDigits = decimals.Length;
// convert value to our format
valueString = val.ToString("N", nfi);
break;
default:
break;
}
return valueString;
}
}
}
class Program
{
static void Main(string[] args)
{
decimal dec = 32445.324777M;
Console.WriteLine(String.Format(new CustomerFormatter(), "{0}", dec));
Console.WriteLine(String.Format(new CustomerFormatter(), "{0:G}", dec));
Console.WriteLine(String.Format(new CustomerFormatter(), "{0:U}", dec));
Console.WriteLine(String.Format(new CustomerFormatter(), "{0:T}", dec));
Console.ReadLine();
}
}

Currency formatting in .NET gives white space between amount and currency

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

Changing the number of integers on a output value after the decimal point

So I'm learning and practicing WP7 application development.
I'm working with integers (currency), and it seems to always display four integers after the decimal place. I'm trying to cut it down to just either ONE or TWO decimal places.
I've been trying to use the "my variable.ToString("C2")" (C for Currency, 2 for number of ints after the decimal)
I'm probably missing something obvious, but please help
decimal number = new decimal(1000.12345678);
string text = number.ToString("#.##");
Output:
1000,12
An other way:
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.CurrencyDecimalDigits = 2;
decimal val = new decimal(1000.12345678);
string text = val.ToString("c", nfi);
When formatting a currency, NumberFormatInfo allows specifying following properties as well:
CurrencyDecimalDigits
CurrencyDecimalSeparator
CurrencyGroupSeparator
CurrencyGroupSizes
CurrencyNegativePattern
CurrencyPositivePattern
CurrencySymbol
See Custom Numeric Format Strings on MSDN for more examples
The "C" format string defines the currency specifier as described on MSDN. This will include the currency symbol for the current culture, or for a specific culture if supplied, e.g.
double amount = 1234.5678;
string formatted = amount.ToString("C", CultureInfo.CreateSpecificCulture("en-US"));
// This gives $1234.56
In your case, it seems that you have a limited set of currency symbols that you support, so I would suggest using the fixed point format specifier "F" instead. By default this will give you 2 decimal points, but you can specify a number to vary this, e.g.
double amount = 1234.5678;
string formatted = amount.ToString("F");
// This gives 1234.56
formatted = amount.ToString("F3");
// This gives 1234.567
Using the fixed point specifier will give you control over the number of decimal points and enable you to concatenate the currency symbol.
The only thing I would add to "sll" answer is to pay attention on Culture (they often forget to mantion this), like this (example)
string text = val.ToString("#.##", CultureInfo.InvariantCulture);
double total = 526.4134
string moneyValue = total.ToString("c");
This will display it in this format: $#.##

Convert.ToInt32() conditional formatting according to string with comma

string str = e.Row.Cells[index].Text;
int value = Int32.Parse(str, NumberStyles.AllowThousands, NumberFormatInfo.InvariantInfo);
if (value >= 100)
e.Row.Cells[index].BackColor = System.Drawing.Color.Green;
Cell values are 168,88 - 125,45 - 75,3
After parsing str returns 16888 - 12545 - 753 , so all of the cells are set as green
how can i compare real values.?
You are using NumberFormatInfo.InvariantInfo. This treats , as thousands separator.
Are you sure this is the correct one? Did you mean to use something like CultureInfo.GetCulture("fr-FR"), where the , is the decimal separator?
Additionally, if you need to preserve the decimal part, why parse to an integer?
This should work better for you:
decimal.Parse(str, NumberStyles.AllowThousands, CultureInfo.GetCulture("fr-FR"));
I think what you're looking for is:
int value = Int32.Parse(str, NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
The NumberFormatInfo tells the Parse function HOW the input should be interpreted. The InvariantInfo reads as Gets the default read-only NumberFormatInfo that is culture-independent (invariant) from msdn.

Categories

Resources