NCalc 指定类型
NCalc specify type
我们有一个使用 Ncalc 计算字符串的通用计算例程。然而,当乘法中的值足够小以至于 Ncalc 将它们视为 int 但结果对于 int 来说太大时,我们 运行 遇到了一个问题。
示例:
var expr = new NCalc.Expression("1740263 * 1234");
object result = expr.Evaluate();
Console.WriteLine(result.ToString());
Console.ReadKey();
这会导致负整数值。
有没有办法强制Ncalc使用long来计算?
我尝试过使用参数,这很有效,但这意味着要对我们的代码进行重大重写才能实现,我希望尽可能避免它。
谢谢
NCalc 使用 Int32
作为整数数据类型,那么您不能强制将数字计算为 Int64
。但是,如果您不使用内置数学函数,而是依赖于 plain 数学运算符,您可以将数字转换为 long
,它会调用正确的运算符。让我们看看:
var expr = new NCalc.Expression("CLng(1740263) * 1234");
expr.EvaluateFunction += delegate(string name, NCalc.FunctionArgs args)
{
// Nostalgic CLng function...
if (String.Equals(name, "CLng", StringComparison.CurrentCultureIgnoreCase))
{
args.HasResult = true;
args.Result = Convert.ToInt64(args.EvaluateParameters()[0]);
}
};
请注意,您不能直接将装箱的 Int32
参数转换为 Int64
,您必须使用 Convert.ToInt64()
或双重转换:(long)(int)args.EvaluateParameters()[0]
。现在您可以检查结果是否正确:
var result = expr.Evaluate();
Console.WriteLine("Result is: {0} (type {1})",
result, result.GetType());
执行正确的类型转换,然后您不需要将两个值强制转换为long
。
注意,你也可以直接使用浮点数(decimal
在NCalc中),你不会有这样的问题:
var expr = new NCalc.Expression("1740263.0 * 1234.0");
您可以使用正则表达式从字符串中提取所有数字,将它们替换为参数,然后将参数设置为转换后的数字。在这个例子中,我将原本的整数替换为十进制。
string myCalculationString = "1000000 * 10000000";
striny myPattern = @"-?\d+(,\d+)*(\.\d+(e\d+)?)?";
MatchCollection matches =
Regex.Matches(convertedCalculation, myPattern );
int matchCount = 0;
convertedCalculation = Regex.Replace(convertedCalculation,
myPattern , m => "[p" + matchCount++ + "]");
for (int i = 0; i < matches.Count; i++)
{
Match match = matches[i];
decimal number = Convert.ToDecimal(match.Value);
expression.Parameters.Add($"p{i}", number);
}
decimal result = (decimal)expression.Evaluate();
注意我没有很好地测试正则表达式,但它似乎适用于 positive/negative 数字,并允许可选的小数点。如果任何数字或结果超出小数范围
,这也会引发错误
我们有一个使用 Ncalc 计算字符串的通用计算例程。然而,当乘法中的值足够小以至于 Ncalc 将它们视为 int 但结果对于 int 来说太大时,我们 运行 遇到了一个问题。
示例:
var expr = new NCalc.Expression("1740263 * 1234");
object result = expr.Evaluate();
Console.WriteLine(result.ToString());
Console.ReadKey();
这会导致负整数值。
有没有办法强制Ncalc使用long来计算?
我尝试过使用参数,这很有效,但这意味着要对我们的代码进行重大重写才能实现,我希望尽可能避免它。
谢谢
NCalc 使用 Int32
作为整数数据类型,那么您不能强制将数字计算为 Int64
。但是,如果您不使用内置数学函数,而是依赖于 plain 数学运算符,您可以将数字转换为 long
,它会调用正确的运算符。让我们看看:
var expr = new NCalc.Expression("CLng(1740263) * 1234");
expr.EvaluateFunction += delegate(string name, NCalc.FunctionArgs args)
{
// Nostalgic CLng function...
if (String.Equals(name, "CLng", StringComparison.CurrentCultureIgnoreCase))
{
args.HasResult = true;
args.Result = Convert.ToInt64(args.EvaluateParameters()[0]);
}
};
请注意,您不能直接将装箱的 Int32
参数转换为 Int64
,您必须使用 Convert.ToInt64()
或双重转换:(long)(int)args.EvaluateParameters()[0]
。现在您可以检查结果是否正确:
var result = expr.Evaluate();
Console.WriteLine("Result is: {0} (type {1})",
result, result.GetType());
执行正确的类型转换,然后您不需要将两个值强制转换为long
。
注意,你也可以直接使用浮点数(decimal
在NCalc中),你不会有这样的问题:
var expr = new NCalc.Expression("1740263.0 * 1234.0");
您可以使用正则表达式从字符串中提取所有数字,将它们替换为参数,然后将参数设置为转换后的数字。在这个例子中,我将原本的整数替换为十进制。
string myCalculationString = "1000000 * 10000000";
striny myPattern = @"-?\d+(,\d+)*(\.\d+(e\d+)?)?";
MatchCollection matches =
Regex.Matches(convertedCalculation, myPattern );
int matchCount = 0;
convertedCalculation = Regex.Replace(convertedCalculation,
myPattern , m => "[p" + matchCount++ + "]");
for (int i = 0; i < matches.Count; i++)
{
Match match = matches[i];
decimal number = Convert.ToDecimal(match.Value);
expression.Parameters.Add($"p{i}", number);
}
decimal result = (decimal)expression.Evaluate();
注意我没有很好地测试正则表达式,但它似乎适用于 positive/negative 数字,并允许可选的小数点。如果任何数字或结果超出小数范围
,这也会引发错误