Allow insertion with special characters in database using c# - c#

I need to allow $(dollar) ,(comma) and .(full stop) into database by converting from string to decimal.Below is the way i need to insert into database.But with my current code it is inserting as given below
decimal d = Convert.ToDecimal(value);
drNew[i] = d;
i++;

You can use this to convert from a string with currency symbol to decimal:
var num = decimal.Parse("$25,529.98", NumberStyles.Currency);
You may also pass the culture if you need/want:
var cultureInfo = new System.Globalization.CultureInfo("en-US");
var num = decimal.Parse("$25,529.98", NumberStyles.Currency, cultureInfo);

Try this one,
int number = 1234567890;
Convert.ToDecimal(number).ToString("#,##0.00");
You will get the result 1,234,567,890.00.

Your approach is backwards and not advisable. Have a hidden field that stores the numeric value and a label that displays the formatted string in currency format. Then save the numeric value.

Related

Decimal Separator In Different Formats creating Issues [duplicate]

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

Make TryParse compatible with comma or dot decimal separator

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
}

Convert a string number with comma to a culture specific double number

NumberFormatInfo numberInfo = CultureInfo.CurrentCulture.NumberFormat;
double result = Convert.ToDouble("2,75", numberInfo);
result = 2.75
My current UI/culture is "de-DE".
Why don't i get 2,75 ?
Because you are not getting a string result, but a double. How you then display that double later is not influenced by your code above.
If you want to see "2,75" on your screen, you need to format the double as a string, adding numberInfo.
Try this to get 2,75:-
string.Format(System.Globalization.CultureInfo.GetCultureInfo("de-DE"), "{0:0.0}", 2.75);
or you can also try this:-
NumberFormatInfo n= new NumberFormatInfo();
n.NumberDecimalSeparator = ",";
n.NumberGroupSeparator = ".";
double d= 2.75;
string s= d.ToString(n); //2,75
You get 2.75. It's only different ways of displaying the number.
The double value contains no information about formatting. It's neither 2.75 nor 2,75, it's just a numeric value.
If you display the number using a culture that uses a comma as decimal separator, you will get what you expect, for example:
Console.WriteLine(result.ToString(CultureInfo.GetCultureInfo(1053)));
Output:
2,75

string.format issue in MVC

var amount="0";
#String.Format("{0:0.00}", amount)
returns "0"
While I was expecting it to return
"0.00"
Formatting a string will just return the string itself, you have to format a number to get it formatted as a number:
var amount = 0;
A variable with implicit type which is assigned an integer value will be an integer, so it won't have a fractional part. You might want to specify the type:
double amount = 0;
Or use a double value:
var amount = 0.0;
Try:
String.Format("{0:#.##}", amount)
OR
String.Format("{0:N2}", amount)
Scratch this - Guffa's answer is correct...
Try this
.ToString("N2")
It will use the CultureInfo to format the number. This means that your thousands separator might be different depending on the used CultureInfo. You can also pass the desired CultureInfo if you want.

Format a double value like currency but without the currency sign (C#)

I feed a textbox a string value showing me a balance that need to be formatted like this:
###,###,###,##0.00
I could use the value.ToString("c"), but this would put the currency sign in front of it.
Any idea how I would manipulate the string before feeding the textbox to achieve the above formatting?
I tried this, without success:
String.Format("###,###,###,##0.00", currentBalance);
Many Thanks,
If the currency formatting gives you exactly what you want, clone a NumberFormatInfo with and set the CurrencySymbol property to "". You should check that it handles negative numbers in the way that you want as well, of course.
For example:
using System;
using System.Globalization;
class Test
{
static void Main()
{
NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
nfi = (NumberFormatInfo) nfi.Clone();
Console.WriteLine(string.Format(nfi, "{0:c}", 123.45m));
nfi.CurrencySymbol = "";
Console.WriteLine(string.Format(nfi, "{0:c}", 123.45m));
}
}
The other option is to use a custom numeric format string of course - it depends whether you really want to mirror exactly how a currency would look, just without the symbol, or control the exact positioning of digits.
string forDisplay = currentBalance.ToString("N2");
Have you tried:
currentBalance.ToString("#,##0.00");
This is the long-hand equivalent of:
currentBalance.ToString("N2");
string result=string.Format("{0:N2}", value); //For result like ### ### ##.##
You can do this with the group separator and the section separator, like this:
currentBalance.ToString("#,0.00;(#,0.00)");
This does not account for culture variances like the answer from #JonSkeet would, but this does mimic decimal place, rounding, thousands separation, and negative number handling that en-US culture currency format produces using a single custom format string.
.NET Fiddle Demo
var result = currentBalance.ToString("C").Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencySymbol, "");
CultureInfo cultureInfo = new CultureInfo("en-US");
cultureInfo.NumberFormat.CurrencySymbol = "Rs.";
Thread.CurrentThread.CurrentCulture = cultureInfo;
decimal devimalValue = 3.45M;
this.Text = devimalValue.ToString("C2"); //Rs.3.45
This may be overkill, but it rounds, formats...
#helper TwoDecimalPlaces(decimal? val)
{
decimal x = 0;
decimal y = 0;
string clas = "text-danger";
if (val.HasValue)
{
x = (decimal)val;
if (val > 0)
{
clas = "";
}
}
y = System.Math.Round(x, 2);
IFormatProvider formatProvider = new System.Globalization.CultureInfo(string.Empty);
<span class="#clas">#string.Format("{0:N2}", y)</span>
}
This simple solution works for me with US currency.
If not needing international currency support use this and replace the $ with the currency symbol(s) to be removed:
// for USD
string result = currentBalance.ToString("C").Replace("$", "")
or
// for EUR
string result = currentBalance.ToString("C").Replace("€", "")

Categories