Wrong decimal places after parsing - c#

I'm trying to load some XY-coordinates from a asc-file. It looks like this:
-55.988544 9382
-53.395804 9403
-50.804601 9433
Then I am converting the coordinates to floats. But somehow f.e. for the first value I get "-55988544.0" instead of "-55.988544".
Here is the code:
private void btngettext_Click(object sender, EventArgs e)
{
StreamReader objStream = new StreamReader("C:\\...\\.asc");
firstLine = objStream.ReadLine();
int i = 0;
/*Split String on Tab,
* will separate words*/
string[] words = firstLine.Split('\t');
richTextBox1.Text = words[0];
foreach(string word in words)
{
if(word != "")
{
Console.WriteLine(word); //the value of the string is "-55.988544" here
//value = float.Parse(word); tried both
value = Convert.ToSingle(word); //here the float value is "-55988544.0"
Console.WriteLine(value.ToString());// "-5,598854E+07"
xyArray[0,i] = value;
i++;
}
}
}
Besides, if I would use objStream.ReadToEnd() or .Read(), how could iterate through lines. Read the values in the first line, save them and proceed to the next line.
Thanks in advance,
BC++

It sounds like your application is running under a culture where "." is a thousands separator rather than a decimal separator. If the source file always uses a ".", then it is better to parse with:
float.Parse(word, System.Globalization.CultureInfo.InvariantCulture);
That will ensure that the parse uses a "." no matter what the machine culture is.

It probably is an issue with the culture settings. Try the following:
var culture = System.Globalization.CultureInfo.InvariantCulture;
value = float.Parse(word, culture);

If your data uses a known, fixed notation for decimal separator etc you should not rely on the defaults of the reading PC. Use
value = float.Parse(word, CultureInfo.InvariantCulture);

Related

Formatting a number in c#

I want to seperate a number with commas. I have tried many ways to do it. But didn't work.
Its already converted to a string and now i want to format the "tot".
GetData getData = new GetData();
string tot = Convert.ToString(getData.Total_Extra(month));
string totVal = (tot).ToString("N",new CultureInfo("en-US"));
LB2.Text = tot.ToString();
You can convert your tot string to a numeric value and then use string.Format to get the desired format:
string tot = "19950000";
string output = string.Format("{0:n2}", Convert.ToInt32(tot));
Debug.WriteLine(output); //19,950,000.00 on my machine
or alternatively:
string output2 = Convert.ToInt32(tot).ToString("n2");
These are both culture specific, so might display differently on different users machines (Indian culture will display 1,99,50,000.00 for example).
If you want to force the three digit comma grouping then you can specify a culture to use:
string output2 = Convert.ToInt32(tot).ToString("n2", CultureInfo.CreateSpecificCulture("en-GB"));
//19,950,000.00 on any machine
It sounds like your tot may not be a numeric value, so you should check this before trying to format it:
string tot = "19950000";
int totInt;
if (Int32.TryParse(tot, out totInt))
{
string output = totInt.ToString("n2", CultureInfo.CreateSpecificCulture("en-GB"));
MessageBox.Show(output);
}
else
{
MessageBox.Show("tot could not be parsed to an Int32");
}

Code not converting text

I have a textbox that allows users to input a decimal values that then gets stored in the a table in the database, this piece of code works in the development environment. I have now published the my project to the server and now is not longer taking the values with the decimal places.
decimal ReceiptAmount;
decimal AmountDue;
decimal Change;
if (!string.IsNullOrEmpty(((TextBox)dl_Item.FindControl("tb_ReceiptAmount")).Text))
{
if (((TextBox)dl_Item.FindControl("tb_ReceiptAmount")).Text.Contains(".") == true)
{
ReceiptAmount = Convert.ToDecimal(((TextBox)dl_Item.FindControl("tb_ReceiptAmount")).Text.Replace(".", ","));
}
else
{
ReceiptAmount = Convert.ToDecimal(((TextBox)dl_Item.FindControl("tb_ReceiptAmount")).Text);
}
}
else
{
ReceiptAmount = 0;
}
if (!string.IsNullOrEmpty(((TextBox)dl_Item.FindControl("tb_AmountDue")).Text))
{
if (((TextBox)dl_Item.FindControl("tb_AmountDue")).Text.Contains(".") == true)
{
AmountDue = Convert.ToDecimal(((TextBox)dl_Item.FindControl("tb_AmountDue")).Text.Replace(".", ","));
}
else
{
AmountDue = Convert.ToDecimal(((TextBox)dl_Item.FindControl("tb_AmountDue")).Text);
}
}
else
{
AmountDue = 0;
}
if (!string.IsNullOrEmpty(((TextBox)dl_Item.FindControl("tb_Change")).Text))
{
if (((TextBox)dl_Item.FindControl("tb_Change")).Text.Contains(".") == true)
{
Change = Convert.ToDecimal(((TextBox)dl_Item.FindControl("tb_Change")).Text.Replace(".", ","));
}
else
{
Change = Convert.ToDecimal(((TextBox)dl_Item.FindControl("tb_Change")).Text);
}
}
else
{
Change = 0;
}
I am not to sure what seems to be the problem with this piece of code. The Textbox are found in a datalist that I loop through to get all of the values.
The Convert.ToDecimal overload that takes a string as input will parse the string using the CultureInfo.CurrentCulture. Probably your server has different regional settings. Depending on regional settings, a comma or point may be either interpreted as a thousand separator (and thus ignored) or as the decimal separator.
Instead, you should use Decimal.Parse directly, providing either a specific culture or the invariant culture, depending on your use case.
Ideally, you'd set the culture of the user somewhere. To achieve this there are multiple approaches, e.g. for ASP.Net Web forms: https://msdn.microsoft.com/en-us/library/bz9tc508.aspx
If you parse the string using the correct culture, you can get rid of the string manipulation for replacing . with ,.
First of all, lines like
if (!string.IsNullOrEmpty(((TextBox)dl_Item.FindControl("tb_ReceiptAmount")).Text))
look very ugly; let's extract a method (copy/paste is very, very bad practice):
private String FindDLText(String controlName) {
var box = dl_Item.FindControl(controlName) as TextBox;
return box == null ? null : box.Text;
}
Then you don't need checking Text.Contains(".") == true, just Replace if you really need it:
private Decimal FindDLValue(String controlName) {
String text = FindDLText(controlName);
if (String.IsNullOrEmpty(text))
return 0.0M;
//TODO: check if you really need this
//text = text.Replace(".", ",");
// you have to specify Culture either InvariantCulture or some predefined one;
// say, new CultureInfo("ru-RU") // <- use Russian Culture to parse this
return Decimal.Parse(text, CultureInfo.InvariantCulture);
}
Finally, you can get
decimal ReceiptAmount = FindDLValue("tb_ReceiptAmount");
decimal AmountDue = FindDLValue("tb_AmountDue");
decimal Change = FindDLValue("tb_Change");
feel the difference: three evident lines and two simple methods.

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
}

custom string format 0,0 with slash or back slash

i have a WPF TextBox that user can type number in that . now i am searching for a string format that can separate TextBox number each 3 point (like 0,0) but i want separate text with Slash or Back Slash or another character. and we do not know how many point our number has.
i am searching for string format not Linq solution or etc . i read Microsoft help but cant find any way .
sample = 123456789 == > 123/456/789 (good) --- 123,456,789 (bad)
Update :
Thanks guys but i search for some thing like this stringformat= {}{0:0,0} etc . i mean dont want use string function like regex , replace or linq or any c# code . i want use a string like {#,#} or etc. see microsoft link in my post i need create a string for my issue.
As the OP insists on the use of String.Format:
string input; //the input of your textbox
int temp = int.Parse(input); //parse your input into an int
//the Format() adds the decimal points, the replace replaces them with the /
string output = String.Format("{0:0,0}", temp).Replace('.', '/');
The important step here is to cast the text of your textbox into an integer, as this simplifies the insertion of the decimal points with String.Format().
Of course, you have to make sure that your textbox is a valid number upon parsing or you may get an exception.
EDIT
So... you have some dynamic-length number and want to format it using a static format-string (as regexes, string replaces, ling or any c# code at all (!) are a no go)? This is impossible.
You HAVE TO have some dynamic code creating a format string somewhere.
Without referencing to regexes or string replaces again, here is some code to create a format string depending on your input number.
This way you have just one String.Format() call. Perhaps you can put the algorithm to create the format string somewhere else and just call it from whereever you need it.
string input; //the input of your textbox
int temp = int.Parse(input); //parse your input into an int
string customString = "{0:";
string tempS = "";
for (int i = 0; i < input.Length; i++)
{
if (i % 3 == 0 && i != 0)
{
tempS += "/";
}
tempS += "#";
}
tempS = new string(tempS.Reverse().ToArray());
customString += tempS;
customString += "}";
string output = String.Format(customString, temp));
You can use a custom NumberFormatInfo. Then use it for ToString with the "n"-format specifier:
NumberFormatInfo nfi = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone();
nfi.NumberGroupSeparator = "/";
nfi.NumberDecimalDigits = 0; // otherwise the "n" format specifier adds .00
Console.Write(123456789.ToString("n", nfi)); // 123/456/789
You can use NumberFormatInfo.NumberGroupSeparator Property
Sample from MSDN
using System;
using System.Globalization;
class NumberFormatInfoSample {
public static void Main() {
// Gets a NumberFormatInfo associated with the en-US culture.
NumberFormatInfo nfi = new CultureInfo( "en-US", false ).NumberFormat;
// Displays a value with the default separator (",").
Int64 myInt = 123456789;
Console.WriteLine( myInt.ToString( "N", nfi ) );
// Displays the same value with a blank as the separator.
nfi.NumberGroupSeparator = " ";
Console.WriteLine( myInt.ToString( "N", nfi ) );
}
}
/*
This code produces the following output.
123,456,789.00
123 456 789.00
*/
for you - set NumberGroupSeparator property to '/'
UPDATE
another sample
var t = long.Parse("123/456/789",NumberStyles.Any, new NumberFormatInfo() { NumberGroupSeparator = "/" });
var output = string.Format(new NumberFormatInfo() { NumberGroupSeparator="/"}, "{0:0,0}", t);

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