string to decimal using extension methods - c#

My string is 1799.00
I want to like this: 1.799,00
But i cannot convert this method.
I'm using this function.
public static decimal ToDecimal(this object str)
{
if (str != null)
{
try
{
return Convert.ToDecimal(str, new CultureInfo("tr-TR"));
}
catch (Exception)
{
return 0;
}
}
else
{
return 0;
}
}

You are, probably, looking for changing formats. Given a decimal as a string in invariant culture representation ("1799.00") you want a string, but in Turkish cutrure representation: ("1.799,00")
// you want to return string in Turkish culture, right?
public static string ToTuskishDecimal(this object value) {
if (null == value)
return null; // or throw exception, or return "0,00" or return "?"
try {
return Convert
.ToDecimal(value, CultureInfo.InvariantCulture)
.ToString("N", CultureInfo.GetCultureInfo("tr-TR"));
}
catch (FormatException) {
return "0,00"; // or "?"
}
}
Test:
decimal d = 1799.00m;
string s = d.ToString(CultureInfo.InvariantCulture);
// 1.799,00
Console.Write(d.ToTuskishDecimal());
// 1.799,00
Console.Write(s.ToTuskishDecimal());
In case you want to return decimal you have to format it manually when printing out:
public static decimal ToDecimal(this object value) {
if (null == value)
return 0.00m;
try {
return Convert.ToDecimal(value, CultureInfo.InvariantCulture);
}
catch (FormatException) {
return 0.00m;
}
}
...
// return me a decimal, please
decimal d = "1799.00".ToDecimal();
// when printing decimal, use Turkish culture
Console.Write(d.ToString("N", CultureInfo.GetCultureInfo("tr-TR")));
you can specify Turkish culture as a default one for the entire thread:
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("tr-TR");
...
// now you don't have to mention Turkish culture
// ...but still have to specify the format
Console.Write(d.ToString("N"));

I use this to obtain a decimal value:
public static decimal toDecimal( string s ) {
decimal res = 0;
decimal.TryParse(s.Replace('.', ','), out res);
return res;
}
In case you want to show the decimal value on the format you ask, try this:
toDecimal("1700.99").ToString("N2")
you will obtain the "1.700,99" string.

I wrote another simple example to obtain a decimal value in Turkish format:
decimal value = 1700.00m;
Console.WriteLine(value.ToString("N", CultureInfo.GetCultureInfo("tr-TR")));

Related

ASP.net, c#, how to check if the value entered is numeric, it could be decimal or simply integer

I am trying to restrict users to enter valid decimal value (No Commas)
what is the best way.
My code :
try{
Convert.ToInt32(stringToCheck)
}
catch
{
//invlaid
}
It fails if the user entered a decimal value, let's say 3.0, although it's a valid value.
If I try
Convert.ToDouble(stringToCheck)
this one fails to catch if the user enters 3,6
Please help!
Thanks.
var stringToCheck = "3,6";
var isDouble =
double.TryParse(stringToCheck,NumberStyles.AllowDecimalPoint,
NumberFormatInfo.InvariantInfo, out double doubleValue);
if (isDouble)
{
// Do stuff if doubleValue variable
}
else
{
// code to run if not double
}
Use regular expression. Here is how.
an example:
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string s = "123";
if (Regex.IsMatch(s, #"^\d+$"))
{
Console.WriteLine("Given string is numeric");
}
else
{
Console.WriteLine("Given string is non-numeric");
}
}
}
You can change the expression to accept any type of numbers.
Update:
The complete solution is:
static bool isNumeric(string s)
{
if (Regex.IsMatch(s, #"^-?[1-9][0-9,\.]+$"))
{
return true;
}
else
{
return false;
}
}
The following code is a test:
Console.WriteLine(isNumeric("0123"));//returns false
Console.WriteLine(isNumeric("2.2"));//returns true
Console.WriteLine(isNumeric("-2.0"));//returns true
Console.WriteLine(isNumeric("123123.2"));//returns true
Console.WriteLine(isNumeric("123sad"));//returns false

Parsing string including currency code?

I know there are many question similar to this one explaining how to parse a string with a currency symbol. Here I would like to do the same but with currency ISO-4217 code (https://en.wikipedia.org/wiki/ISO_4217).
decimal.Parse("45,000.00 USD", System.Globalization.NumberStyles.AllowDecimalPoint)
decimal.Parse("45.00 USD")
decimal.Parse("USD 45.00")
decimal.Parse("USD45.00")
decimal.Parse("45.00USD")
decimal.Parse("45.00 RUP")
decimal.Parse("IND 45.00")
decimal.Parse("45.00 EUR")
decimal.Parse("INR 45.00")
I was thinking about a solution with regular expression but maybe there are more direct solution or something already exist in .NET lib. I don't know.
You can use NumberFormatInfo.
See the example i have written below.
var nmfi = new NumberFormatInfo();
nmfi.NegativeSign = "-";
nmfi.CurrencySymbol = "USD";
nmfi.CurrencyDecimalSeparator = ".";
nmfi.CurrencyGroupSeparator = ",";
var result1 = decimal.Parse("USD45.00", NumberStyles.Currency, nmfi);
var result2 = decimal.Parse("45.00USD", NumberStyles.Currency, nmfi);
var result3 = decimal.Parse("45.00 USD", NumberStyles.Currency, nmfi);
At this moment I have no better solution than mine
public static decimal Parse(string s)
{
if (string.IsNullOrEmpty(s))
throw new ArgumentNullException("s is null");
var match = Regex.Match(s, "[A-Z]{3}");
if (!match.Success)
throw new FormatException("s is not in the correct format. Currency code is not found.");
s = s.Replace(match.Value, string.Empty); // I don't like this line
decimal value = decimal.Parse(s, NumberStyles.Currency);
return value;
}
In my code I use a Money Object. Money is composed by a decimal value and a 3 character currency code.
public static Money Parse(string s)
{
if (string.IsNullOrEmpty(s))
throw new ArgumentNullException("s is null");
var match = Regex.Match(s, "[A-Z]{3}");
if (!match.Success)
throw new FormatException("s is not in the correct format. Currency code is not found.");
s = s.Replace(match.Value, string.Empty); // I don't like this line
decimal value = decimal.Parse(s, NumberStyles.Currency);
return new Money(value, (CurrencyCode)Enum.Parse(typeof(CurrencyCode), match.Value));
}
Your best bet here is to bundle the decimal number with it's format so that it is easy for you to know what currency the value is for. I have created IsoDecimal helper struct to help with such thing.
void Main()
{
var arr = new string[]
{
"45,000.00 USD" ,
"45.00 USD" ,
"USD 45.00" ,
"USD45.00" ,
"45.00USD" ,
"45.00 RUP" ,
"IND 45.00" ,
"45.00 EUR" ,
"INR 45.00"
};
foreach (var num in arr)
{
Console.WriteLine(new IsoDecimal(num).ToString());
}
}
The struct is here.
public struct IsoDecimal
{
private NumberFormatInfo numberFormat { get; set; }
private decimal value { get; set; }
public IsoDecimal(string strValue)
{
string strNumber = Regex.Match(strValue, #"[\d.\-,]+").Value;
string code = Regex.Match(strValue, #"[A-Z]+").Value;
numberFormat = new NumberFormatInfo();
numberFormat.NegativeSign = "-";
numberFormat.CurrencyDecimalSeparator = ".";
numberFormat.CurrencyGroupSeparator = ",";
numberFormat.CurrencySymbol = code;
value = Decimal.Parse(strNumber);
}
public static implicit operator decimal(IsoDecimal isoDecimal)
{
return isoDecimal.value;
}
public override string ToString()
{
return ToString("C");
}
public string ToString(string format)
{
return value.ToString(format, numberFormat);
}
}
The struct allows you to assign its value to a decimal variable at will in case you need it, and it overrides Object.ToString to that it is seamless to integrate and work with.
You could use regex
Decimal.Parse(Regex.Match("USD 45.00", #"(\d+(\.\d+)?)").Value);

String.Format Currency for K, M and B

If a currency amount is very large, I'm trying to abbreviate it.
For example:
if (amt > 1000000)
{
decimal d = (decimal)Math.Round(amt / 1000, 0);
return String.Format("{0:C0}", d) + " K";
}
If a number is given over 1 million, it will take off the last 3 digits and replace with a K. Works just fine when the currency symbol (like $ is on the left hand side)
However, some currency symbols get put on the right hand side.
So instead of a nice looking $100 K for USD, I'd get 100 € K for French Euros.
How can I change the format to put the K immediately after the numbers, and before the currency symbol.
Seems like it might be a step too far. Any ideas?
I would create a class with the IFormatProvider like this
public class MoneyFormat: IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}
public string Format(string fmt, object arg, IFormatProvider formatProvider)
{
if (arg.GetType() != typeof(decimal))
try
{
return HandleOtherFormats(fmt, arg);
}
catch (FormatException e)
{
throw new FormatException(string.Format("The format of '{0}' is invalid", fmt), e);
}
string ufmt = fmt.ToUpper(CultureInfo.InvariantCulture);
if (!(ufmt == "K"))
try
{
return HandleOtherFormats(fmt, arg);
}
catch (FormatException e)
{
throw new FormatException(string.Format("The format of '{0}' is invalid", fmt), e);
}
decimal result;
if (decimal.TryParse(arg.ToString(), out result))
{
if (result >= 1000000)
{
decimal d = (decimal)Math.Round(result / 10000, 0);
CultureInfo clone = (CultureInfo)CultureInfo.CurrentCulture.Clone();
string oldCurrSymbol = clone.NumberFormat.CurrencySymbol;
clone.NumberFormat.CurrencySymbol = "";
return String.Format(clone, "{0:C0}", d).Trim() + " K" + oldCurrSymbol;
}
}
else
return string.Format("{0:C0}", result) + " K";
}
private string HandleOtherFormats(string format, object arg)
{
if (arg is IFormattable)
return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture);
else if (arg != null)
return arg.ToString();
else
return string.Empty;
}
}
Then you can call it in your format like so:
return string.Format( new MoneyFormat(), "{0:K}", amt);
You can then tweek the way you want to represent your "K" or other reference symbols that you want to add
CultureInfo("fr-fr") : 100 K€
CultureInfo("en-us") : 100 K$
CultureInfo("ru-RU") : 100 Kр.
You can use the CurrencyPositivePattern to determine if the currency symbol comes before or after the number. Then you can modify the CurrencySymbol to suit your needs.
decimal amt = 10000000;
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); //set up France as current culture
NumberFormatInfo NFI = CultureInfo.CurrentCulture.NumberFormat;
string currencySymbol = NFI.CurrencySymbol;
int currencyPosition = NFI.CurrencyPositivePattern;
if (amt > 1000000)
{
if (currencyPosition == 3) // n $
{
NFI.CurrencySymbol = "K " + currencySymbol;
}
decimal d = (decimal)Math.Round(amt / 1000, 0);
string output = d.ToString("c");
}
I know this is not the best implementation of a custom number format, but this is just to get the idea across.
See:
NumberFormatInfo.CurrencyPositivePattern Property

Avoid round off decimals in Datagridview control

In the Datagridview I have a column "C" which is product of Column "A" and "B".
Example
Column A Value - 8.14
Column B Value - 0.2
Now the column C value is 12.296 and after decimal I want to show first two numbers like
12.29 without rounding to 12.30.
Below is the code i used to achieve the above result.
public class CustomFormatter : 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)
{
// Check whether this is an appropriate callback
if (!this.Equals(formatProvider))
return null;
if (arg == null) return null;
string numericString = arg.ToString();
decimal result = 0;
if (Decimal.TryParse(numericString, out result))
{
return ((Math.Truncate(result * 100)) / 100).ToString();
}
else
{
return null;
}
}
}
private void gvItemDetails_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
try
{
if (e.ColumnIndex == gvItemDetails.Columns["Vat Amount"].Index)
{
gvItemDetails[e.ColumnIndex, e.RowIndex].Value = String.Format(new CustomFormatter(), "{0}", e.Value);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
When i put a break point on cellformatting code..i can see the code is repeated continously but not returning any stackoverflow exception. When i remove the breakpoint its working.
Can you please advice what might be the problem or suggest any other alternative to prevent it from rounding an show 12.29 not 12.30.
Thanks,
Prathap.
First, i tried to use the same method which you used. It works perfectly fine for me and produces desired "12.29".
string numericString = "12.2963";
string truncatedString = string.Empty;
decimal result = 0;
if (Decimal.TryParse(numericString, out result))
{
truncatedString = ((Math.Truncate(result * 100)) / 100).ToString();
}
In case, above method doesn't work for you, another simple alternative would be to use string.substring (this will be useful only when intermediate decimal value is not required for you).
string numericString = "12.2963";
string truncatedString = string.Empty;value
int endIndex = numericString.IndexOf('.');
truncatedString = numericString.Substring(0, endIndex + 3);
Update:
Though i haven't tested it, you should be able to define format provider this way :
this.dataGridView1.Columns["XYZ"].DefaultCellStyle.FormatProvider = new CustomFormatter();
and for format (here format string will have pre-defined meaning) :
this.dataGridView1.Columns["XYZ"].DefaultCellStyle.Format = "c";
Update 2:
Unfortunately, even if you are using FormatProvider, you still need to handle cellformatting event; Check This.
Good news is that you don't need to use FormatProvider for this. Try following format, it should work for you:
this.dataGridView1.Columns["XYZ"].DefaultCellStyle.Format = "0.##";

C# How to format a double to one decimal place without rounding

I need to format a double value to one decimal place without it rounding.
double value = 3.984568438706
string result = "";
What I have tried is:
1)
result = value.ToString("##.##", System.Globalization.CultureInfo.InvariantCulture) + "%";
// returns 3.98%
2)
result = value.ToString("##.#", System.Globalization.CultureInfo.InvariantCulture) + "%";
// returns 4%
3)
result = value.ToString("##.0", System.Globalization.CultureInfo.InvariantCulture) + "%";
// returns 4.0%
4) (Following other suggestions)
value = (value / 100);
result = String.Format("{0:P1}", Math.Truncate(value * 10000) / 10000);
// returns 4.0%
result = string.Format("{0:0.0%}",value); // returns 4.0%
What I need to display is the value 3.9%
Thanks for any help in advance.
result=string.Format("{0:0.0}",Math.Truncate(value*10)/10);
I would make a utility method to handle this:
static double Truncate(double value, int digits)
{
double mult = System.Math.Pow(10.0, digits);
return System.Math.Truncate(value * mult) / mult;
}
You could then do:
result = Truncate(value, 1).ToString("##.#", System.Globalization.CultureInfo.InvariantCulture) + "%";
Note that you may also want Math.Floor instead of truncate - but it depends on how you want negative values handled.
I know this is a old thread but I've just had to do this. While the approaches here work I want a easy way to be able to affect a lot of calls so using the Math.Truncate on all the calls to string.format wasn't really a good option.
Thus, I made a custom format provider which would allow me to add truncation to the formatting string, eg
string.format(new FormatProvider(), "{0:T}", 1.1299); // 1.12
string.format(new FormatProvider(), "{0:T(3)", 1.12399); // 1.123
string.format(new FormatProvider(), "{0:T(1)0,000.0", 1000.9999); // 1,000.9
The implementation is pretty simple and is easily extendible to other requirements.
public class FormatProvider : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof (ICustomFormatter))
{
return this;
}
return null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (arg.GetType() != typeof (double))
{
try
{
return HandleOtherFormats(format, arg);
}
catch (FormatException e)
{
throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
}
}
if (format.StartsWith("T"))
{
int dp = 2;
int idx = 1;
if (format.Length > 1)
{
if (format[1] == '(')
{
int closeIdx = format.IndexOf(')');
if (closeIdx > 0)
{
if (int.TryParse(format.Substring(2, closeIdx - 2), out dp))
{
idx = closeIdx + 1;
}
}
else
{
throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
}
}
}
double mult = Math.Pow(10, dp);
arg = Math.Truncate((double)arg * mult) / mult;
format = format.Substring(idx);
}
try
{
return HandleOtherFormats(format, arg);
}
catch (FormatException e)
{
throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
}
}
private string HandleOtherFormats(string format, object arg)
{
if (arg is IFormattable)
{
return ((IFormattable) arg).ToString(format, CultureInfo.CurrentCulture);
}
return arg != null ? arg.ToString() : String.Empty;
}
}
ToString() doesn't do it. You have to add extra code. The other answers show math approaches, my approach below is kind of outside-the-box.
string result = value.ToString();
Console.WriteLine("{0}", result.Substring(0, result.LastIndexOf('.') + 2));
This is a fairly simple brute force approach, but it does the trick when the decimal is a '.'. Here's an extension method to ease the pain (and deals with the decimal point).
public static class Extensions
{
public static string ToStringNoTruncate(this double me, int decimalplaces = 1)
{
string result = me.ToString();
char dec = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator[0];
return result.Substring(0, result.LastIndexOf(dec) + decimalplaces + 1);
}
}
( Math.Truncate( ( value * 10 ) ) / 1000 ).ToString( "#.#%" )
Just use modulo operator + built in ToString:
result = (value - (value % 0.1)).ToString("N1") + "%";

Categories

Resources