How I can get the value that the user inputs to round to two decimal places. I tried to use.ToString("N2") but it gave me an error of {cannot convert string to System.IFormatProvider}. I can't seem to find a solution to this error.
code is here:
using System;
using System.Text.RegularExpressions;
namespace _selfTest
{
class Program
{
public static void Main(string[] args)
{
const string formula = #"^\d+\.?\d+?\%$";
percentages(formula, Console.ReadLine());
}
public static void percentages(string bottle, string flower)
{
Regex newRegular = new Regex(bottle);
bool input = newRegular.IsMatch(flower);
if (input)
Console.WriteLine("This Percentage Is Correct! " + bottle);
else
Console.WriteLine("This Percentage Is Incorrect... " + bottle);
Console.ReadLine();
}
}
}
You could use Decimal.TryParse method. And then you can use standard numeric format string "N2"
string consoleInput = Console.ReadLine();
if(Decimal.TryParse(consoleInput, out decimal parsedInput))
{
string resultString = parsedInput.ToString("N2");
}
else
{
// handling bad input
}
Your solution is just 2 steps away
Parsing the user input to decimal format
Then rounding off to 2 decimal places
.cs
static void Main(string[] args)
{
//Parse User input
var inputValue = Console.ReadLine();
inputValue = inputValue.Split('%')[0]; //To handle the trailing % sign
decimal outputValue;
var style = NumberStyles.Any;
var culture = CultureInfo.InvariantCulture;
if (Decimal.TryParse(inputValue, style, culture, out outputValue))
Console.WriteLine("Converted '{0}' to {1}.", inputValue, outputValue);
else
Console.WriteLine("Unable to convert '{0}'.", inputValue);
//Rounding off 2 decimal places
var roundedValue = Math.Round(outputValue, 2);
Console.WriteLine(roundedValue);
Console.Read();
}
Note
If you know ahead of time what culture you expect your inputs to be in you can specify that using culture info
var culture = new CultureInfo("en-US");// or ("fr-FR")
Related
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);
user input:
"I have 3 apples"
output:
"I"
"have"
"6"
"apples"
My C#:
static void Main(string[] args)
{
Console.WriteLine("Enter a string...");
string delimeter = " ";
string input = Console.ReadLine();
string[] output = input.Split(Convert.ToChar(delimeter));
foreach (var substring in output)
{
Console.WriteLine(substring);
}
Console.Read();
}
I need help getting on the right track. My code only breaks the sentence apart using space as a delimiter.
Give it a try
foreach (var substring in output)
{
int value;
if(int.TryParse(substring, out value)){
value = value * 2;
input = input.Replace(substring, value.ToString());
}
}
Console.WriteLine(input);
You first need to check if your spitted string is a number, if it is then multiple by 2 and replace it in your input variable to get the expected output.
Can you try followoing?
static void Main(string[] args)
{
Console.WriteLine("Enter a string...");
string delimeter = " ";
string input = Console.ReadLine();
var result = System.Text.RegularExpression.Regex.Replace(input,"\d+", match=>(int.Parse(match.Value)*2).ToString(CultureInfo.InvariantCulture));
Console.WriteLine(result);
Console.Read();
}
Here is an algorithm for example.
// an extension method to check if a string is all decimal digits
public static class StringHelper {
public static bool IsNumeric(this string str)
{
if (str.IsNullOrWhiteSpace()) return false;
return str.All(char.IsNumber);
}
}
...
static void Main(string[] args)
{
Console.WriteLine("Enter a string...");
string delimeter = " ";
string input = Console.ReadLine();
string[] output = input.Split(Convert.ToChar(delimeter));
foreach (var substring in output)
{
if (substring.IsNumeric())
{
substring = (int.Parse(substring) * 2).ToString();
}
Console.Write(substring);
}
Console.WriteLine();
Console.Read();
}
Please note that the code is only checking if a substring contains only decimal digits. It's not prepared to handle any number with decimal point for example, and it's also not completely safe. The code is not tested, and is ment only for example purposes.
I intentionally showed a code without using Regular Expressions, but if you're interested, check out the other answers for that alternative.
I have the number 123.1234567890129.
I want the result to be 123.123456789012 without the last digit being rounded.
I've tried:
("123.1234567890129").ToString("G15") //123.123456789013
One way that you could do this is to round to 16 like this
("123.1234567890129").ToString("G16").Substring(0, 16);
Since you said double.
Since doubles can have ANY number of digits you must round in some way. (you either round down, as inferred or you round up as in practice for this case)
Since you imply you only want to see the number of precise digits, you must find out how many digits are on each side of the decimal point (0 to 15 on either side)
An extenstion to round down
public static class DoubleExtensions
{
public static double RoundDown(this double value, int numDigits)
{
double factoral = Math.Pow(10, numDigits);
return Math.Truncate(value * factoral) / factoral;
}
}
test case
const int totalDigits = 15;
// why start with a string??
string somestring = "123.1234567890129";
const int totalDigits = 15;
// since the title says 'convert a double to a string' lets make it a double eh?
double d = double.Parse(somestring);
int value = (int)d;
double digitsRight = d - value;
int numLeft = (d - digitsRight).ToString().Count();
int numRight = totalDigits - numLeft;
double truncated = d.RoundDown(numRight);
string s = truncated.ToString("g15");
You can create custom FormatProvider and then create your implementation.
class Program
{
static void Main(string[] args)
{
double number = 123.1234567890129;
var result = string.Format(new CustomFormatProvider(15), "{0}", number);
}
}
public class CustomFormatProvider : IFormatProvider, ICustomFormatter
{
private readonly int _numberOfDigits;
public CustomFormatProvider(int numberOfDigits)
{
_numberOfDigits = numberOfDigits;
}
public object GetFormat(Type formatType) => formatType == typeof(ICustomFormatter) ? this : null;
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (!Equals(formatProvider))
return null;
if (!(arg is double))
{
return null;
}
var input = ((double)arg).ToString("R");
return input.Length > _numberOfDigits + 1 ? input.Substring(0, _numberOfDigits + 1) : input; // +1 because of dot
}
Unfortunately you cannot do in this way:
var result = number.ToString(new CustomFormatProvider(15));
because of value types limitation.. Double supports only CultureInfo and NumberFormatInfo formatters. If you pass different formatter it will return default instance: NumberFormatInfo.CurrentInfo'. You can make small workaround by usingstring.Format` method.
New to the community. First answer here. :)
I think you are looking for something like this. Works with or without decimal. This will cut the digits after the 15th digit only irrespective of length of the number. You can get the user to decide the accuracy by getting the precision value as a user input and performing that condition check accordingly. I used 15 because you mentioned it. Let me know if it works for you. Cheers!
string newstr;
int strlength,substrval;
double number;
string strnum = "123.1234567890129";
strlength = strnum.Length;
if(strlength>15)
{
strlength = 15;
}
substrval = strlength;
foreach(char x in strnum)
{
if(x=='.')
{
substrval++;
}
}
newstr = strnum.Substring(0, substrval);
number=Convert.ToDouble(newstr);
Alife Goodacre, code is printing "123.12345678901" insted "123.123456789012"
there should be Substring(0, 16) insted of Substring(0, 15)
Convert.ToDouble("123.1234567890129").ToString("G16").Substring(0, 16)
OutPut Screen with Code.
I have this number in textbox "84,8441546842904" how to convert in 84,8 or 84,84 on button click event?
If by this you mean you want to parse the value and round it to a certain number of decimal places:
double value = Math.Round(double.Parse(textbox.Text), 2);
will parse the text and round it to 2 decimal places. You may need to use a System.Globalization.CultureInfo object when parsing to account for your local culture's number formatting.
See http://msdn.microsoft.com/en-us/library/75ks3aby.aspx
It almost looks like you are trying to trim the number to 1 or 2 precision (isn't the ',' used in some countries as the US '.'?). If this is what you're after, you can use Double.Parse to convert it to a Double and then look into the string format options described here to format it back to the textbox.
I use this kind of functions to validate user input.
This approach to the problem also respects user culture number format!
namespace Your_App_Namespace
{
public static class Globals
{
public static double safeval = 0; // variable to save former value!
public static bool isPositiveNumeric(string strval, System.Globalization.NumberStyles NumberStyle)
// checking if string strval contains positive number in USER CULTURE NUMBER FORMAT!
{
double result;
boolean test;
if (strval.Contains("-")) test = false;
else test = Double.TryParse(strval, NumberStyle, System.Globalization.CultureInfo.CurrentCulture, out result);
// if (test == false) MessageBox.Show("Not positive number!");
return test;
}
public static string numstr2string(string strval, string nofdec)
// conversion from numeric string into string in USER CULTURE NUMBER FORMAT!
// call example numstr2string("12.3456", "0.00") returns "12.34"
{
string retstr = 0.ToString(nofdec);
if (Globals.isPositiveNumeric(strval, System.Globalization.NumberStyles.Number)) retstr = double.Parse(strval).ToString(nofdec);
else retstr = Globals.safeval.ToString(nofdec);
return retstr;
}
public static string number2string(double numval, string nofdec)
// conversion from numeric value into string in USER CULTURE NUMBER FORMAT!
// call example number2string(12.3456, "0.00") returns "12.34"
{
string retstr = 0.ToString(nofdec);
if (Globals.isPositiveNumeric(numval.ToString(), System.Globalization.NumberStyles.Number)) retstr = numval.ToString(nofdec);
else retstr = Globals.safeval.ToString(nofdec);
return retstr;
}
}
// Other Your_App_Namespace content
}
// This is the way how to use those functions
// function to call when TextBox GotFocus
private void textbox_clear(object sender, System.Windows.RoutedEventArgs e)
{
TextBox txtbox = e.OriginalSource as TextBox;
// save original value
Globals.safeval = double.Parse(txtbox.Text);
txtbox.Text = "";
}
// function to call when TextBox LostFocus
private void textbox_change(object sender, System.Windows.RoutedEventArgs e)
{
TextBox txtbox = e.OriginalSource as TextBox;
// text from textbox into sting with checking and string format
txtbox.Text = Globals.numstr2string(txtbox.Text, "0.00");
}
double i = 0;
if (double.TryParse(tbxNumber.Text,out i)) {
MessageBox.Show("number is " + i.ToString());
}
How to parse string to decimal so it would work for both formats - w/ commas and periods?
[Fact]
public void foo(){
var a="1,1";
var b="1.1";
Assert.Equal(Parse(a),Parse(b));
}
private decimal Parse(string s){
return decimal.Parse(s,NumberStyles.Any,
CultureInfo.InvariantCulture);
}
output:
Test 'Unit.Sandbox.foo' failed: Assert.Equal() Failure
Expected: 11
Actual: 1,1
You could try that:
private decimal Parse(string s){
s = s.Replace(",", CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator);
return decimal.Parse(s,NumberStyles.Any,
CultureInfo.InvariantCulture);
}
How about this?
private static decimal Parse(string s)
{
s = s.Replace(",", ".");
return decimal.Parse(s);
}
You should get the desired result by modifying the Currency decimal separator to a comma before a parse on a comma decimal string. There are some food resources here:
http://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.currencydecimalseparator.aspx#Y888
You could alternatively implement your own Iformatprovider as discussed here:
http://msdn.microsoft.com/en-us/library/t7xswkc6.aspx
http://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.aspx
Oh, or you could do a dirty hack and simply run a string replace on "," with "." ;)
If you have an English-language operating system, this method converts a decimal number with a comma to a dot. If you have Russian, the method converts a decimal number with a dot to a comma.
Console.Write("Input number: ");
string? input = Console.ReadLine();
decimal number = ConvertNumberToCurrentLocale(input);
Console.WriteLine("Result: " + number);
decimal ConvertNumberToCurrentLocale(string? input)
{
string separator = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
switch (separator)
{
case ".":
input = input?.Replace(",", ".");
break;
case ",":
input = input?.Replace(".", ",");
break;
}
decimal.TryParse(input, out var number);
return number;
}