C# 我计算基本插入表达式的算法的缺陷在哪里?
我正在尝试实施一个类似于 输入:C# 我计算基本插入表达式的算法的缺陷在哪里?,c#,algorithm,parsing,recursion,C#,Algorithm,Parsing,Recursion,我正在尝试实施一个类似于 输入: ~1^(2~&3)|1 69 11111 -12 [whatever NOT 69 XOR (11111 NAND -12) OR 69 equals] 输出: ~1^(2~&3)|1 69 11111 -12 [whatever NOT 69 XOR (11111 NAND -12) OR 69 equals] 所有位运算符具有相同的优先级,从左到右求值。我正在构建的算法基本上是 Get number n1 (or evaluati
~1^(2~&3)|1 69 11111 -12
[whatever NOT 69 XOR (11111 NAND -12) OR 69 equals]
输出:
~1^(2~&3)|1 69 11111 -12
[whatever NOT 69 XOR (11111 NAND -12) OR 69 equals]
所有位运算符具有相同的优先级,从左到右求值。我正在构建的算法基本上是
Get number n1 (or evaluation of expression in parenthesis)
Set result = n1
Get operator o1
Get number n2 (or evaluation of expression in parenthesis)
Set result = result op n2
Get operator o2
Get number n3 (or evaluation of expression in paranthesis)
Set result = result o2 n3
Etcetera
我还没有完全完成,但我所拥有的至少应该能够进行评估
((1)) 69
这将导致
69
我已经测试过了
(1) 69
导致
69
这意味着我只需要找出嵌套括号的问题所在
我的代码的相关部分,经过很好的注释,是。。。请容忍我在这里
private static long? EvalInner ( string eqtn, Tuple<int,int> eqtnBnds, Dictionary<int,long> eqtnArgs)
{
// eqtn: Equation to be parsed
// eqtnBnds: Bounds that define sub-equation being evaluated.
// eqtnargs: Equation arguments
// Parses and returns the evaluation of the equation eqtn in the bounds [eqtnBands.Item1, eqtnBnds.Item2)
// Handle case of empty sub-equation:
if (eqtnBnds.Item1 == eqtnBnds.Item2) throw new Exception(String.Format("Encountered empty equation at index {0}", eqtnBnds.Item1));
long? result = null;
char? lastop = null; // last operator found
bool negateNextNum = false;
PARSEMODE CURMODE = PARSEMODE.NUM; // beginning of equation should be a number since the form of the equation is
// <NUM><OPER><NUM><OPER>...<OPER><NUM>
int curidx = eqtnBnds.Item1, offend = eqtnBnds.Item2;
while ( curidx < offend )
{
switch ( CURMODE )
{
case PARSEMODE.NUM: // Expecting character at current index to be the beginning of a
{
if ( eqtn[curidx] >= '0' && eqtn[curidx] <= '9' ) // beginning of the int corresponding to the argument index
{
int begidx = curidx;
// Increment curidx to one after the last digit or the end of the subequation
while ( ++curidx < offend && eqtn[curidx] >= '0' && eqtn[curidx] <= '9' );
// Try to get an integer representation of the argument. If an error is encountered in that parsing,
// throw an error. If the argument is one within the range of arguments given in the command line,
// get its value and update result accordingly. If not, throw an error.
int argnum;
if ( Int32.TryParse(eqtn.Substring(begidx, curidx - begidx), out argnum) )
{
if (eqtnArgs.ContainsKey(argnum))
{
result = (result != null ? BinOpEval(result, lastop, eqtnArgs[argnum]) : eqtnArgs[argnum]);
if (negateNextNum)
{
result = ~result;
negateNextNum = false;
}
}
else
throw new Exception(String.Format("Argument {0} found in the equation beginning at index {1} is out-of-bounds",
argnum,
begidx)
);
}
else
{
throw new Exception(String.Format("Trouble parsing argument number that begins at index {0}",
begidx)
);
}
CURMODE = PARSEMODE.OPER;
}
else if ( eqtn[curidx] == Calculator.OPENPAREN ) // beginning of subequation in paranthesis
{
int begidx = curidx, netparens = 1;
while ( ++curidx < offend && netparens != 0 )
{
if ( eqtn[curidx] == Calculator.OPENPAREN ) ++netparens;
else if ( eqtn[curidx] == Calculator.CLOSEPAREN ) --netparens;
}
if ( netparens != 0 ) // didn't find closing parenthesis
throw new Exception(String.Format("Couldn't find closing paranthesis for opening paranthesis at index {0}",
begidx)
);
long? presult = null; // to be the result of the evaluated subequation between the set of parenthesis
try { presult = EvalInner(eqtn,new Tuple<int, int>(++begidx, curidx - begidx),eqtnArgs); }
catch ( Exception e ) { throw e; }
result = (result != null ? BinOpEval(result,lastop,presult) : presult);
if (negateNextNum)
{
result = ~result;
negateNextNum = false;
}
// Upon leaving this else-if block, curidx should be 1 after the closing paranthesis
// Expect operate to following closing paranthesis
CURMODE = PARSEMODE.OPER; // expecting operator after parens
}
else if ( eqtn[curidx] == Calculator.NOT ) // NOT symbol preceding number
{
negateNextNum = !negateNextNum;
++curidx;
// CURMODE stays as num
}
else // unexpected character where beginning of number expected
{
throw new Exception(String.Format("Expected beginning of number at index {0}, instead got {1}",
curidx,
eqtn[curidx])
);
}
break;
}
case PARSEMODE.OPER:
{
// ...
正在打印错误
Error: Encountered empty equation at index 2
让我来分析一下我的逻辑:
首先,curidx=0
,eqtn[curidx]='('
和CURMODE=PARSEMODE.NUM
。这导致我们进入块
else if ( eqtn[curidx] == Calculator.OPENPAREN ) // beginning of subequation in paranthesis
{
// ...
}
else if ( eqtn[curidx] == Calculator.OPENPAREN ) // beginning of subequation in paranthesis
{
int begidx = curidx, netparens = 1;
while ( ++curidx < offend && netparens != 0 )
{
if ( eqtn[curidx] == Calculator.OPENPAREN ) ++netparens;
else if ( eqtn[curidx] == Calculator.CLOSEPAREN ) --netparens;
}
if ( eqtn[curidx] >= '0' && eqtn[curidx] <= '9' ) // beginning of the int corresponding to the argument index
{
// ...
}
在块部分的末尾
int begidx = curidx, netparens = 1;
while ( ++curidx < offend && netparens != 0 )
{
if ( eqtn[curidx] == Calculator.OPENPAREN ) ++netparens;
else if ( eqtn[curidx] == Calculator.CLOSEPAREN ) --netparens;
}
我们最终回到了街区
else if ( eqtn[curidx] == Calculator.OPENPAREN ) // beginning of subequation in paranthesis
{
// ...
}
else if ( eqtn[curidx] == Calculator.OPENPAREN ) // beginning of subequation in paranthesis
{
int begidx = curidx, netparens = 1;
while ( ++curidx < offend && netparens != 0 )
{
if ( eqtn[curidx] == Calculator.OPENPAREN ) ++netparens;
else if ( eqtn[curidx] == Calculator.CLOSEPAREN ) --netparens;
}
if ( eqtn[curidx] >= '0' && eqtn[curidx] <= '9' ) // beginning of the int corresponding to the argument index
{
// ...
}
之后,很明显,我们已经处理了1
,将其与参数69
关联,并通过调用堆栈传递回输出
哪里出错了?这里元组的第二个元素是子方程的长度还是它的上界
presult = EvalInner(eqtn,new Tuple<int, int>(++begidx, curidx - begidx),eqtnArgs);
presult=EvalInner(eqtn,新元组(++begidx,curidx-begidx),eqtnArgs);
简单地使用两个清晰的命名参数可能会更有帮助,但基于您在递归调用之前的使用情况,它看起来似乎是上界,但您正在传递一个长度
也许这是唯一的问题?不确定。这里元组的第二个元素是指子方程的长度还是它的上界
presult = EvalInner(eqtn,new Tuple<int, int>(++begidx, curidx - begidx),eqtnArgs);
presult=EvalInner(eqtn,新元组(++begidx,curidx-begidx),eqtnArgs);
简单地使用两个清晰的命名参数可能会更有帮助,但基于您在递归调用之前的使用情况,它看起来似乎是上界,但您正在传递一个长度
也许这是唯一的问题?不确定。这里元组的第二个元素是指子方程的长度还是它的上界
presult = EvalInner(eqtn,new Tuple<int, int>(++begidx, curidx - begidx),eqtnArgs);
presult=EvalInner(eqtn,新元组(++begidx,curidx-begidx),eqtnArgs);
简单地使用两个清晰的命名参数可能会更有帮助,但基于您在递归调用之前的使用情况,它看起来似乎是上界,但您正在传递一个长度
也许这是唯一的问题?不确定。这里元组的第二个元素是指子方程的长度还是它的上界
presult = EvalInner(eqtn,new Tuple<int, int>(++begidx, curidx - begidx),eqtnArgs);
presult=EvalInner(eqtn,新元组(++begidx,curidx-begidx),eqtnArgs);
简单地使用两个清晰的命名参数可能会更有帮助,但基于您在递归调用之前的使用情况,它看起来似乎是上界,但您正在传递一个长度
也许这是唯一的问题?不确定。如果您的代码确实显示了相关的工作,并且修复它可能并不简单,那么我宁愿编写一个递归算法来提供您想要的功能 代码的基本思想如下:
启动解析过程。它执行基本的 有效性检查(即相同数量的开始括号和结束括号) 决定是否需要对执行实际分析的函数进行新调用。所有这些调用都递归地生成最终输出removeAllParen
只处理一组括号,最外部的括号(例如,从“((1))”)输出为“((1))”。它 查找第一个左括号和最后一个右括号removeOneParen
由于您的代码确实显示了相关的工作,并且修复它可能并不简单,所以我更喜欢编写一个递归算法来提供您想要的功能 代码的基本思想如下:
启动解析过程。它执行基本的 有效性检查(即相同数量的开始括号和结束括号) 决定是否需要对执行实际分析的函数进行新调用。所有这些调用都递归地生成最终输出removeAllParen
只处理一组括号,最外部的括号(例如,从“((1))”)输出为“((1))”。它 查找第一个左括号和最后一个右括号removeOneParen
由于您的代码确实显示了相关的工作,并且修复它可能并不简单,所以我更喜欢编写一个递归算法来提供您想要的功能 代码的基本思想如下:
启动解析过程。它执行基本的 有效性检查(即相同数量的开始括号和结束括号) 决定磨砺removeAllParen