0

I am currently using ncalc library to do several evaluation and get the result out of it.

Right now I have found a problem where if I have a price in the format "1,234.01" it will fail to evaluate my expression.

The current workaround I've used was to remove the , but I was wondering if there is way to evaluate a currency without having to remove the , for example:

decimal price = 0;
if (!decimal.TryParse(iPrice.Text, out price))
{
    MessageBox.Show("Price is not formatted correctly...");
    return;
}

decimal currency = 0;
if (!decimal.TryParse(iCurrency.Text, out currency))
{
    MessageBox.Show("Currency is not formatted correctly...");
    return;
}

string formula = iFormula.Text.Replace("Price", price.ToString("n2")).Replace("Currency", currency.ToString("n2"));
Expression exp = new Expression(formula);
exp.Evaluate();

Evaluate fails because of the , from my price where if I remove it, it works just fine.

Sample of the formula:

(((Price+12,9)+((Price+12,9)*0,05)+(((Price+12,9)+((Price+12,9)*0,05))*0,029)+0,45)*Currency)

Stacktrace as requested:

NCalc.EvaluationException was unhandled
  Message=mismatched input ',' expecting ')' at line 1:4
mismatched input ',' expecting ')' at line 1:20
mismatched input ',' expecting ')' at line 1:43
mismatched input ',' expecting ')' at line 1:59
missing EOF at ')' at line 1:77
  Source=NCalc
  StackTrace:
       at NCalc.Expression.Evaluate()
Guapo
  • 3,446
  • 9
  • 36
  • 63

2 Answers2

2

Your question is still unclear to me, but I suspect you can fix this just by changing the format you're using when replacing. Change this:

string formula = iFormula.Text.Replace("Price", price.ToString("n2")) 
                              .Replace("Currency", currency.ToString("n2"));

to this:

string formula = iFormula.Text.Replace("Price", price.ToString("f2")) 
                              .Replace("Currency", currency.ToString("f2"));

That will use the "fixed point" format instead of the "number" format. You won't get grouping. Note that grouping isn't part of the number itself - it's part of how you format a number.

I'd also be tempted to specify the invariant culture explicitly, by the way.

As an aside: I haven't used NCalc myself, but if it's really forcing you to specify the numeric values in an expression as text, that sounds pretty poor. I'd expect some sort of parameterization (as per most SQL providers, for example) which should make all of this go away.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Yes that solves it using `f2` instead... Now I understood what you were trying to tell me on the other answer's comment ;) – Guapo Jul 02 '12 at 06:25
0

No, you cannot have a separator in your decimal literal. The compiler will confuse it with declaring multiple variables with the same type like:

decimal price = 1m, tax = 234m; 

If it was a string, however, you could parse it like:

decimal price = Decimal.Parse("1,234.0", CultureInfo.InvariantCulture); 

EDIT: my answer above was directed to the code sample in the first version of the question. Now that the question has been edited:

You can control the string representation of your decimal values using the Decimal.ToString(string format, IFormatProvider provider) method overload. This allows you to specify a standard or custom format string. In your case, it sounds like you need to have 2 decimal digits separated using a dot, and no group separators (no commas). So you could say:

price.ToString("F2", CultureInfo.InvariantCulture) // ex. result: "1234.56"

CultureInfo.InvariantCulture is important if you need a dot separator regardless of the current culture. If you don't specify that, the output could be "1234,56" depending on the current culture (e.g. in case of european cultures like de-DE, or fr-FR).

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
  • price and currency are set by the user on a text box and I am using decimal.TryParse to convert into decimal, the above decimal values were mere samples to expose my issue. – Guapo Jul 02 '12 at 05:57
  • @leppie do you see the statement: `decimal price = 1,123.01m;` ? – Eren Ersönmez Jul 02 '12 at 05:57
  • 1
    @Guapo You didn't mention that in the Q. Your current code sample is trying to assign a decimal using a literal that includes a comma. And you say "it works when I remove the comma". My answer is directed to your question _as is_. If you edit your question, I'll edit my answer. – Eren Ersönmez Jul 02 '12 at 06:02
  • @Guapo: So where does it actually fail? At parsing time, or in the expression? It's *really* important to make that clear, as it sounds like you may have actually removed all of the *useful* code in your question, replacing it with invalid code... – Jon Skeet Jul 02 '12 at 06:02
  • @ErenErsönmez: You are talking about the C# compiler, while the OP is passing text to ncalc's interpreter. – leppie Jul 02 '12 at 06:04
  • @JonSkeet it fails at the expression ONLY when the price contains a comma like I explained above, so I don't see where I have removed anything here, I am just posting the relevant information related to it. In fact its a brand new project with barely nothing on it but 4 labels, 1 button, 3 text box (1 for price, 1 for currency, 1 for the formula). – Guapo Jul 02 '12 at 06:12
  • 1
    @Guapo: You removed the parsing. By the time a value has been parsed, *it doesn't contain a comma*. If the parsing of everything that contains a comma happens *before* the expression, then it's very unclear what the problem is. (Although it's all confused by the way you're then formatting `price` again... why?) If it's the parsing of the *expression itself* that's the problem (where again, you've got commas) it's worth knowing that. Basically, there are two places where commas could occur: in your expression or in the values. You haven't made it clear which you care about. – Jon Skeet Jul 02 '12 at 06:17
  • @JonSkeet I don't think we are understanding each other, I have a text box with let's say `1,123.01`, then I parse it and have the `decimal price` all good right ? Now I want to replace on my formula where I have the TEXT `Price` with my `decimal price`, so I am using the above replace which turns the decimal into a string with 2 decimal places but then again when that value is on the thousands it will contain a comma, which breaks the expression. And as what I think is a dirty workaround I am using another replace to remove that comma which I don't want to. – Guapo Jul 02 '12 at 06:21
  • @Guapo: My point is that the fact that the *textbox* has a comma in it is completely irrelevant. After parsing, there's no sign of that comma. You're getting a comma in your *expression* because of the format string you're using - you'd get it even if the textbox just contained "1123.01". See my answer for an alternative. – Jon Skeet Jul 02 '12 at 06:23
  • @Guapo so the line `decimal price = 1,123.01m;` doesn't exist in your code. Instead, you have a decimal variable `price` and you pass that variable to `TryParse`, correct? – Eren Ersönmez Jul 02 '12 at 06:25
  • @ErenErsönmez Like I mentioned on my 2nd comment of your answer, those were mere to represent the issue. – Guapo Jul 02 '12 at 06:27
  • @Guapo when you were presenting the issue, you introduced another unrelated code error, and I answered to that error. In order to avoid the same confusion for other readers, you should edit the code sample and remove that line of code, or change it like: `decimal price = Decimal.Parse("1,234.0", CultureInfo.InvariantCulture);` Not trying to argue, just trying to improve your question. – Eren Ersönmez Jul 02 '12 at 06:37