Click here to Skip to main content
15,887,214 members
Articles / Programming Languages / C#
Article

C# Expression Parser using RPN

Rate me:
Please Sign up or sign in to vote.
4.57/5 (26 votes)
17 Jan 20045 min read 210.7K   7.4K   85   32
Design & implementation of an Expression Parser using RPN in C#.

Introduction

The aim of this article is to demonstrate an interface-based programming paradigm in the design and implementation of a simple Expression Parser & Evaluator using RPN in C#. The intended audience skill set would be Beginner to Intermediate.

Background

For introduction about Expressions & Reverse Polish Notation, refer to this article - Expression Evaluator: using RPN by lallous, in the C++/MFC section.

Design Description

(All code referred here is inside RPNParser.cs file.)

Interfaces

Every expression is made of operands and operators. These are reflected in the interfaces - IOperand and IOperator.

  • IArithmeticOperations defines methods for binary arithmetic operators (+, -, *, \, %).
  • IComparisonOperations defines methods for all comparison operators (>, >=, <, <=, ==, !=).
  • ILogicalOperations defines methods for logical operators (&& , ||).

The idea behind these interfaces is as follows -

Each Operand supports a set of Operations and the Operators evaluate a pair of Operands using the Operations supported by the two Operands.

E.g. A Long Operand supports Arithmetic and Comparison Operations, whereas a String might support only Comparison Operations. Boolean Operands support only the Logical Operations.

An Operator like + needs only to know that it has to call the Plus method on an IOperand implementing the IArithmeticOperations interface. This keeps the algorithm of expression parsing & evaluation (in this case the RPN sequencing) separated from the data type that does the actual evaluations and hence makes it very extensible to newer data types.

Operands

Operand class is an abstract base class implementing the IOperand interface and additionally providing data storage.

LongOperand is an Operand class specific to Long & Int (Int64 and Int32) types of operands and implements the IArithmeticOperations, IComparisonOperations interfaces.

BoolOperand is an Operand class specific to bool type of operands and implements only the ILogicalOperations interface.

OperandHelper is a static class providing object factory functionality to create appropriate Operand objects based on the Type passed to it (OperandHelper.CreateOperand).

For new types of Operands like Decimal/String or user-defined types, e.g. a Matrix, this factory method would have to be extended.

Operators

IOperator defines one method called Eval and is used to evaluate the LHS and RHS of the expression.

Operator is an abstract base class implementing this interface and provides data storage for the operator.

ArithmeticOperator, ComparisonOperator, LogicalOperator are operator classes to support IArithmeticOperations, IComparisonOperations, ILogicalOperations respectively.

OperatorHelper is a helper class providing object factory functionality for creation of appropriate Operator objects (OperatorHelper.CreateOperator). This class provides services to determine operator-precedence. This is based on the relative indexes of the operators defined in the m_AllOps variable. It also provides Regular Expressions used during parsing of the input expression string. E.g. The regex [=<>!]{1,2} is used to parse for Comparison operators.

Expression Parsing

The Tokenizer class provides functionality of parsing the input expression string using regular expressions.

The TokenEnumerator class supports the IEnumerator interface and is used to loop through the various tokens in the input expression string. The tokens in the expression are returned to the caller as Token objects.

The given expression can be parsed as either Arithmetic or Logical or Comparison Expression Types. This is controlled by the enums ExpressionType::ET_ARITHMETIC, ExpressionType::ET_COMPARISON and ExpressionType::ET_LOGICAL. A combination of these enum types can also be given.

E.g. To parse the expression as all of these, pass ExpressionType.ET_ARITHMETIC| ExpressionType.ET_COMPARISON|ExpressionType.ET_LOGICAL to the Tokenizer c'tor.

The generation of the RPN sequence is in the RPNParser::GetPostFixNotation method and it uses the algorithm as described in the above mentioned C++ article. The return value is an ArrayList consisting of Operands and Operators in the RPN sequence.

This method takes an argument bFormula that determines if the expression being parsed is a formula (in the form of x+y*z/t) or has direct values (3+6*7/2). If the expression is not a formula, then the values are extracted by this method and stored in the Token object for later evaluation. If the expression is a formula, then the values for the corresponding variables need to be passed separately as a hashtable for evaluation.

Expression Evaluation

RPNParser::EvaluateRPN is the method performing actual evaluation of the RPN generated by the RPNParser::GetPostFixNotation method and is again based on the algorithm described in the above mentioned C++ article. This method takes as input the ArrayList with the RPN sequence and if the expression is a formula, a hashtable with values for the variables in the expression.

Usage

A typical usage of the parser would be as follows -

C#
RPNParser parser = new RPNParser();

string szExpression = @"((2+3)*2<10 || 1!=1) && 2*2==4";

parser.EvaluateExpression( szExpression, 
    Type.GetType("System.Int64" ), false, null );

The attached code contains a small form-based application to test the logic.

It uses the RPN_Parser::Convert2String() method to get a string representation of the RPN sequence.

Extensibility

The Parser can be easily extended to support new Operand types and Operators by subclassing the Operand and Operator classes. Since the Parsing and Evaluation logic works totally on interfaces, typically nothing would have to be changed there. Of course, the factory classes need to be extended to support the new types and if adding new operators, the regular expressions used & their precedence information present inside the Operatorhelper class would have to be modified accordingly.

Hope someone out there finds this useful.

Current Shortcomings

  1. Unary operators (+,-,!) not handled.
  2. Does not yet support expressions having mixture of variables and values (e.g. x+y/3*z%2 ).
  3. Bitwise & and | not handled.
  4. Does not handle a combo expression with multiple braces as just one of the ExpressionTypes?

    // E.g. ((2+3)*2<10 || 1!=1) && 2*2==4 as just a logical expression cannot be done.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionGiving some examples Pin
Member 139396026-Aug-18 12:47
Member 139396026-Aug-18 12:47 
Questionpossibility to reuse the source code? Pin
Member 1228813111-Apr-16 5:48
Member 1228813111-Apr-16 5:48 
QuestionDivide error Pin
Imanloo27-May-14 22:00
Imanloo27-May-14 22:00 
GeneralMy vote of 5 Pin
stofel9-Sep-13 1:51
stofel9-Sep-13 1:51 
GeneralVB eqivalent Pin
coarist20-Jun-13 2:48
coarist20-Jun-13 2:48 
QuestionConditional operator Pin
Member 89200266-Aug-12 21:17
Member 89200266-Aug-12 21:17 
GeneralMy vote of 4 Pin
staarkannan20-Dec-10 23:05
staarkannan20-Dec-10 23:05 
GeneralHere is the updated code for unary operator Not(!). [modified] Pin
staarkannan20-Dec-10 23:02
staarkannan20-Dec-10 23:02 
GeneralYou did great job !!! Pin
actyrol24-Aug-10 5:32
actyrol24-Aug-10 5:32 
QuestionAny restriction to use this code? Pin
sree1234518-Mar-10 10:44
sree1234518-Mar-10 10:44 
AnswerRe: Any restriction to use this code? Pin
Member 122881318-Apr-16 0:15
Member 122881318-Apr-16 0:15 
QuestionAdding Exponent Operator Pin
Azra sultana7-Jun-09 4:12
Azra sultana7-Jun-09 4:12 
GeneralDecimal Value Cannot Evaluate Pin
RobertChan20003-May-09 12:51
RobertChan20003-May-09 12:51 
Questionsome bugs? Pin
Canic23-Apr-09 16:31
Canic23-Apr-09 16:31 
GeneralOperator Precedence Pin
cmptrkemist13-Dec-07 19:48
cmptrkemist13-Dec-07 19:48 
GeneralMinus unary operator support + string comparison [modified] Pin
zitun21-Jun-06 22:08
zitun21-Jun-06 22:08 
GeneralUnary operator support Pin
stuallenii5-May-06 5:59
stuallenii5-May-06 5:59 
I've added support for the negation operator (-). It gets converted into a (~) and placed in the RPN expression as such. Some tweaking was done to the evaluator to look for unary and handle that situation.

thanks for this code, helped me out in a big way, hope someone finds the unary support worthwhile and decides to add upon it.

using System;<br />
using System.Collections;<br />
using System.Text;<br />
using System.Text.RegularExpressions;<br />
<br />
#region RPN<br />
///<br />
/// Summary description for RPNParser.<br />
///<br />
public class RPNParser<br />
{<br />
    public RPNParser()<br />
    {<br />
    }<br />
    public object SetupExpression(string szExpr, Type varType, bool bFormula, Hashtable htValues)<br />
    {<br />
        ArrayList arrExpr = GetPostFixNotation(szExpr, varType, bFormula);<br />
        return Convert2String(arrExpr);<br />
    }<br />
    public object EvaluateExpression(string szExpr, Type varType, bool bFormula, Hashtable htValues)<br />
    {<br />
        ArrayList arrExpr = GetPostFixNotation(szExpr, varType, bFormula);<br />
        return EvaluateRPN(arrExpr, varType, htValues);<br />
    }<br />
<br />
    #region RPN_Parser<br />
    ///<br />
    /// Algo of GetPostFixNotation (source : Expression Evaluator : using RPN by lallous<br />
    /// in the C++/MFC section of www.CodeProject.com.<br />
    /// 1. Initialize an empty stack (string stack), prepare input infix expression and clear RPN string<br />
    /// 2. Repeat until we reach end of infix expression<br />
    /// I. Get token (operand or operator); skip white spaces<br />
    /// II. If token is:<br />
    /// a. Left parenthesis: Push it into stack<br />
    /// b. Right parenthesis: Keep popping from the stack and appending to<br />
    /// RPN string until we reach the left parenthesis.<br />
    /// If stack becomes empty and we didn't reach the left parenthesis<br />
    /// then break out with error "Unbalanced parenthesis"<br />
    /// c. Operator: If stack is empty or operator has a higher precedence than<br />
    /// the top of the stack then push operator into stack.<br />
    /// Else if operator has lower precedence then we keep popping and<br />
    /// appending to RPN string, this is repeated until operator in stack<br />
    /// has lower precedence than the current operator.<br />
    /// d. An operand: we simply append it to RPN string.<br />
    /// III. When the infix expression is finished, we start popping off the stack and<br />
    /// appending to RPN string till stack becomes empty.<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    public ArrayList GetPostFixNotation(string szExpr, Type varType, bool bFormula)<br />
    {<br />
        Stack stkOp = new Stack();<br />
        ArrayList arrFinalExpr = new ArrayList();<br />
        string szResult = "";<br />
        string szLastItem = "";<br />
        bool bApplyNegative = false;<br />
<br />
        Tokenizer tknzr = null;<br />
        switch (varType.ToString())<br />
        {<br />
            case "System.Int32":<br />
            case "System.Int64":<br />
                tknzr = new Tokenizer(szExpr, ExpressionType.ET_ARITHMETIC |<br />
                ExpressionType.ET_COMPARISON |<br />
                ExpressionType.ET_LOGICAL);<br />
                break;<br />
            case "System.String":<br />
                tknzr = new Tokenizer(szExpr, ExpressionType.ET_COMPARISON);<br />
                break;<br />
        }<br />
<br />
<br />
<br />
        foreach (Token token in tknzr)<br />
        {<br />
            string szToken = token.Value.Trim();<br />
            if (szToken.Length == 0)<br />
                continue;<br />
            switch (varType.ToString())<br />
            {<br />
                case "System.Int32":<br />
                case "System.Int64":<br />
                    if (!OperatorHelper.IsOperator(szToken))<br />
                    {<br />
                        Operand oprnd = OperandHelper.CreateOperand(szToken, varType);<br />
                        oprnd.ExtractAndSetValue(szToken, bFormula);<br />
                        arrFinalExpr.Add(oprnd);<br />
<br />
                        szResult += szToken;<br />
                        szLastItem = szToken;<br />
                        continue;<br />
                    }<br />
                    break;<br />
                case "System.String":<br />
                    if (!OperatorHelper.IsComparisonOperator(szToken))<br />
                    {<br />
                        Operand oprnd = OperandHelper.CreateOperand(szToken, varType);<br />
                        oprnd.ExtractAndSetValue(szToken, bFormula);<br />
                        arrFinalExpr.Add(oprnd);<br />
<br />
                        szResult += szToken;<br />
                        szLastItem = szToken;<br />
                        continue;<br />
                    }<br />
<br />
                    break;<br />
            }<br />
<br />
            string szOp = szToken;<br />
            if (szOp == "(")<br />
            {<br />
                stkOp.Push(szOp);<br />
            }<br />
            else if (szOp == ")")<br />
            {<br />
                string szTop;<br />
                while ((szTop = (string)stkOp.Pop()) != "(")<br />
                {<br />
                    IOperator oprtr = OperatorHelper.CreateOperator(szTop);<br />
                    arrFinalExpr.Add(oprtr);<br />
<br />
                    szResult += szTop;<br />
<br />
                    if (stkOp.Count == 0)<br />
                        throw new RPN_Exception("Unmatched braces!");<br />
                }<br />
            }<br />
            else<br />
            {<br />
                if (szOp == "-" && (!StringContentCheck.IsAlphaNumeric(szLastItem) || szLastItem==""))<br />
                {<br />
                    bApplyNegative = true;<br />
                    //Operand oprnd = OperandHelper.CreateOperand("0", varType);<br />
                    //oprnd.ExtractAndSetValue("0", bFormula);<br />
                    //arrFinalExpr.Add(oprnd);<br />
                    <br />
                    //szResult += "0";<br />
                    //stkOp.Push("(");<br />
                    stkOp.Push("~");<br />
                    //string szTop;<br />
                    //while ((szTop = (string)stkOp.Pop()) != "(")<br />
                    //{<br />
                    //    IOperator oprtr = OperatorHelper.CreateOperator(szTop);<br />
                    //    arrFinalExpr.Add(oprtr);<br />
<br />
                    //    szResult += szTop;<br />
<br />
                    //    if (stkOp.Count == 0)<br />
                    //        throw new RPN_Exception("Unmatched braces!");<br />
                    //}<br />
                }<br />
                else<br />
                {<br />
                    if (stkOp.Count == 0 || (string)stkOp.Peek() == "("<br />
                    || OperatorHelper.IsHigherPrecOperator(szOp, (string)stkOp.Peek()))<br />
                    {<br />
                        stkOp.Push(szOp);<br />
                    }<br />
                    else<br />
                    {<br />
                        while (stkOp.Count != 0)<br />
                        {<br />
                            if (OperatorHelper.IsLowerPrecOperator(szOp, (string)stkOp.Peek())<br />
                            || OperatorHelper.IsEqualPrecOperator(szOp, (string)stkOp.Peek()))<br />
                            {<br />
                                string szTop = (string)stkOp.Peek();<br />
                                if (szTop == "(")<br />
                                    break;<br />
                                szTop = (string)stkOp.Pop();<br />
<br />
                                IOperator oprtr = OperatorHelper.CreateOperator(szTop);<br />
                                arrFinalExpr.Add(oprtr);<br />
<br />
                                szResult += szTop;<br />
                            }<br />
                            else<br />
                                break;<br />
                        }<br />
                        stkOp.Push(szOp);<br />
                    }<br />
                }<br />
            }<br />
            szLastItem = szToken;<br />
        }<br />
        while (stkOp.Count != 0)<br />
        {<br />
            string szTop = (string)stkOp.Pop();<br />
            if (szTop == "(")<br />
                throw new RPN_Exception("Unmatched braces");<br />
<br />
            IOperator oprtr = OperatorHelper.CreateOperator(szTop);<br />
            arrFinalExpr.Add(oprtr);<br />
<br />
            szResult += szTop;<br />
        }<br />
        return arrFinalExpr;<br />
    }<br />
<br />
    #endregion<br />
<br />
    public string Convert2String(ArrayList arrExpr)<br />
    {<br />
        string szResult = "";<br />
        foreach (object obj in arrExpr)<br />
        {<br />
            szResult += obj.ToString() + " ";<br />
        }<br />
        return szResult;<br />
    }<br />
<br />
<br />
    #region RPN_Evaluator<br />
<br />
    ///<br />
    /// Algo of EvaluateRPN (source : Expression Evaluator : using RPN by lallous<br />
    /// in the C++/MFC section of www.CodeProject.com.<br />
    /// 1. Initialize stack for storing results, prepare input postfix (or RPN) expression.<br />
    /// 2. Start scanning from left to right till we reach end of RPN expression<br />
    /// 3. Get token, if token is:<br />
    /// I. An operator:<br />
    /// a. Get top of stack and store into variable op2; Pop the stack<br />
    /// b. Get top of stack and store into variable op1; Pop the stack<br />
    /// c. Do the operation expression in operator on both op1 and op2<br />
    /// d. Push the result into the stack<br />
    /// II. An operand: stack its numerical representation into our numerical stack.<br />
    /// 4. At the end of the RPN expression, the stack should only have one value and<br />
    /// that should be the result and can be retrieved from the top of the stack.<br />
    ///<br />
    /// Expression to be evaluated in RPNotation with<br />
    /// single character variables<br />
    /// Values for each of the variables in the expression<br />
    ///<br />
    public object EvaluateRPN(ArrayList arrExpr, Type varType, Hashtable htValues)<br />
    {<br />
        // initialize stack (integer stack) for results<br />
        Stack stPad = new Stack();<br />
        // begin loop : scan from left to right till end of RPN expression<br />
        foreach (object var in arrExpr)<br />
        {<br />
            Operand op1 = null;<br />
            Operand op2 = null;<br />
            IOperator oprtr = null;<br />
            // Get token<br />
            // if token is<br />
            if (var is IOperand)<br />
            {<br />
                // Operand : push onto top of numerical stack<br />
                stPad.Push(var);<br />
            }<br />
            else if (var is IOperator)<br />
            {<br />
                if (OperatorHelper.IsUnaryOperator(((Operator)var).ToString()))<br />
                {<br />
                    // Operator :<br />
                    // Pop top of stack into var 1<br />
                    op1 = (Operand)stPad.Pop();<br />
                    if (htValues != null)<br />
                    {<br />
                        op1.Value = htValues[op1.Name];<br />
                    }<br />
                    // Do operation exp for 'this' operator on var1 and var2<br />
                    oprtr = (IOperator)var;<br />
                    IOperand opRes = oprtr.Eval(op1);<br />
                    // Push results onto stack<br />
                    stPad.Push(opRes);<br />
                }<br />
                else<br />
                {<br />
                    // Operator :<br />
                    // Pop top of stack into var 1 - op2 first as top of stack is rhs<br />
                    op2 = (Operand)stPad.Pop();<br />
                    if (htValues != null)<br />
                    {<br />
                        op2.Value = htValues[op2.Name];<br />
                    }<br />
                    // Pop top of stack into var 2<br />
                    op1 = (Operand)stPad.Pop();<br />
                    if (htValues != null)<br />
                    {<br />
                        op1.Value = htValues[op1.Name];<br />
                    }<br />
                    // Do operation exp for 'this' operator on var1 and var2<br />
                    oprtr = (IOperator)var;<br />
                    IOperand opRes = oprtr.Eval(op1, op2);<br />
                    // Push results onto stack<br />
                    stPad.Push(opRes);<br />
                }<br />
            }<br />
        }<br />
        // end loop<br />
        // stack ends up with single value with final result<br />
        return ((Operand)stPad.Pop()).Value;<br />
    }<br />
    #endregion<br />
}<br />
#endregion<br />
<br />
#region UtilClasses<br />
<br />
///<br />
/// The given expression can be parsed as either Arithmetic or Logical or<br />
/// Comparison ExpressionTypes. This is controlled by the enums<br />
/// ExpressionType::ET_ARITHMETIC, ExpressionType::ET_COMPARISON and<br />
/// ExpressionType::ET_LOGICAL. A combination of these enum types can also be given.<br />
/// E.g. To parse the expression as all of these, pass<br />
/// ExpressionType.ET_ARITHMETIC|ExpressionType.ET_COMPARISON|ExpressionType.ET_LOGICAL<br />
/// to the Tokenizer c'tor.<br />
///<br />
[Flags]<br />
public enum ExpressionType<br />
{<br />
    ET_ARITHMETIC = 0x0001,<br />
    ET_COMPARISON = 0x0002,<br />
    ET_LOGICAL = 0x0004<br />
}<br />
///<br />
/// Currently not used.<br />
///<br />
public enum TokenType<br />
{<br />
    TT_OPERATOR,<br />
    TT_OPERAND<br />
}<br />
///<br />
/// Represents each token in the expression<br />
///<br />
public class Token<br />
{<br />
    public Token(string szValue)<br />
    {<br />
        m_szValue = szValue;<br />
    }<br />
    public string Value<br />
    {<br />
        get<br />
        {<br />
            return m_szValue;<br />
        }<br />
    }<br />
    string m_szValue;<br />
}<br />
///<br />
/// Is the tokenizer which does the actual parsing of the expression.<br />
///<br />
public class Tokenizer : IEnumerable<br />
{<br />
    public Tokenizer(string szExpression)<br />
        : this(szExpression, ExpressionType.ET_ARITHMETIC |<br />
    ExpressionType.ET_COMPARISON |<br />
    ExpressionType.ET_LOGICAL)<br />
    {<br />
    }<br />
    public Tokenizer(string szExpression, ExpressionType exType)<br />
    {<br />
        m_szExpression = szExpression;<br />
        m_exType = exType;<br />
        m_RegEx = new Regex(OperatorHelper.GetOperatorsRegEx(m_exType));<br />
        m_strarrTokens = SplitExpression(szExpression);<br />
    }<br />
    public IEnumerator GetEnumerator()<br />
    {<br />
        return new TokenEnumerator(m_strarrTokens);<br />
    }<br />
    public string[] SplitExpression(string szExpression)<br />
    {<br />
        return m_RegEx.Split(szExpression);<br />
    }<br />
    ExpressionType m_exType;<br />
    string m_szExpression;<br />
    string[] m_strarrTokens;<br />
    Regex m_RegEx;<br />
}<br />
<br />
///<br />
/// Enumerator to enumerate over the tokens.<br />
///<br />
public class TokenEnumerator : IEnumerator<br />
{<br />
    Token m_Token;<br />
    int m_nIdx;<br />
    string[] m_strarrTokens;<br />
<br />
    public TokenEnumerator(string[] strarrTokens)<br />
    {<br />
        m_strarrTokens = strarrTokens;<br />
        Reset();<br />
    }<br />
    public object Current<br />
    {<br />
        get<br />
        {<br />
            return m_Token;<br />
        }<br />
    }<br />
    public bool MoveNext()<br />
    {<br />
        if (m_nIdx >= m_strarrTokens.Length)<br />
            return false;<br />
<br />
        m_Token = new Token(m_strarrTokens[m_nIdx]);<br />
        m_nIdx++;<br />
        return true;<br />
    }<br />
    public void Reset()<br />
    {<br />
        m_nIdx = 0;<br />
    }<br />
}<br />
#region Exceptions<br />
///<br />
/// For the exceptions thrown by this module.<br />
///<br />
public class RPN_Exception : ApplicationException<br />
{<br />
    public RPN_Exception()<br />
    {<br />
    }<br />
    public RPN_Exception(string szMessage)<br />
        : base(szMessage)<br />
    {<br />
    }<br />
    public RPN_Exception(string szMessage, Exception innerException)<br />
        : base(szMessage, innerException)<br />
    {<br />
    }<br />
}<br />
#endregion<br />
#endregion<br />
<br />
#region Interfaces<br />
public interface IOperand { }<br />
public interface IOperator<br />
{<br />
    IOperand Eval(IOperand lhs, IOperand rhs);<br />
    IOperand Eval(IOperand lhs);<br />
}<br />
<br />
public interface IArithmeticOperations<br />
{<br />
    // to support {"+", "-", "~", "*", "/", "%"} operators<br />
    IOperand Plus(IOperand rhs);<br />
    IOperand Minus(IOperand rhs);<br />
    IOperand Negate();<br />
    IOperand Multiply(IOperand rhs);<br />
    IOperand Divide(IOperand rhs);<br />
    IOperand Modulo(IOperand rhs);<br />
}<br />
public interface IComparisonOperations<br />
{<br />
    // to support {"==", "!=","<", "<=", ">", ">="} operators<br />
    IOperand EqualTo(IOperand rhs);<br />
    IOperand NotEqualTo(IOperand rhs);<br />
    IOperand LessThan(IOperand rhs);<br />
    IOperand LessThanOrEqualTo(IOperand rhs);<br />
    IOperand GreaterThan(IOperand rhs);<br />
    IOperand GreaterThanOrEqualTo(IOperand rhs);<br />
}<br />
public interface ILogicalOperations<br />
{<br />
    // to support {"||", "&&" } operators<br />
    IOperand OR(IOperand rhs);<br />
    IOperand AND(IOperand rhs);<br />
}<br />
#endregion<br />
<br />
#region Operands<br />
///<br />
/// Base class for all Operands. Provides datastorage<br />
///<br />
public abstract class Operand : IOperand<br />
{<br />
    public Operand(string szVarName, object varValue)<br />
    {<br />
        m_szVarName = szVarName;<br />
        m_VarValue = varValue;<br />
    }<br />
    public Operand(string szVarName)<br />
    {<br />
        m_szVarName = szVarName;<br />
    }<br />
    public override string ToString()<br />
    {<br />
        return m_szVarName;<br />
    }<br />
    public abstract void ExtractAndSetValue(string szValue, bool bFormula);<br />
    public string Name<br />
    {<br />
        get<br />
        {<br />
            return m_szVarName;<br />
        }<br />
        set<br />
        {<br />
            m_szVarName = value;<br />
        }<br />
    }<br />
    public object Value<br />
    {<br />
        get<br />
        {<br />
            return m_VarValue;<br />
        }<br />
        set<br />
        {<br />
            m_VarValue = value;<br />
        }<br />
    }<br />
    protected string m_szVarName = "";<br />
    protected object m_VarValue = null;<br />
}<br />
///<br />
/// Operand corresponding to the Long (Int32/Int64) datatypes.<br />
///<br />
public class LongOperand : Operand, IArithmeticOperations, IComparisonOperations<br />
{<br />
    public LongOperand(string szVarName, object varValue)<br />
        : base(szVarName, varValue)<br />
    {<br />
    }<br />
    public LongOperand(string szVarName)<br />
        : base(szVarName)<br />
    {<br />
    }<br />
    public override string ToString()<br />
    {<br />
        return m_szVarName;<br />
    }<br />
    public override void ExtractAndSetValue(string szValue, bool bFormula)<br />
    {<br />
        m_VarValue = !bFormula ? Convert.ToInt64(szValue) : 0;<br />
    }<br />
    /// IArithmeticOperations methods. Return of these methods is again a LongOperand<br />
    public IOperand Plus(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.Plus : rhs");<br />
        LongOperand oprResult = new LongOperand("Result", Type.GetType("System.Int64"));<br />
        oprResult.Value = (long)this.Value + (long)((Operand)rhs).Value;<br />
        return oprResult;<br />
    }<br />
    public IOperand Minus(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.Minus : rhs");<br />
        LongOperand oprResult = new LongOperand("Result", Type.GetType("System.Int64"));<br />
        oprResult.Value = (long)this.Value - (long)((Operand)rhs).Value;<br />
        return oprResult;<br />
    }<br />
    public IOperand Negate()<br />
    {<br />
        LongOperand oprResult = new LongOperand("Result", Type.GetType("System.Int64"));<br />
        oprResult.Value = (long)this.Value * -1;<br />
        return oprResult;<br />
    }<br />
    public IOperand Multiply(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new ArgumentException("Argument invalid in LongOperand.Multiply : rhs");<br />
        LongOperand oprResult = new LongOperand("Result", Type.GetType("System.Int64"));<br />
        oprResult.Value = (long)this.Value * (long)((Operand)rhs).Value;<br />
        return oprResult;<br />
    }<br />
    public IOperand Divide(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.Divide : rhs");<br />
        LongOperand oprResult = new LongOperand("Result", Type.GetType("System.Int64"));<br />
        oprResult.Value = (long)this.Value / (long)((Operand)rhs).Value;<br />
        return oprResult;<br />
    }<br />
    public IOperand Modulo(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.Modulo : rhs");<br />
        LongOperand oprResult = new LongOperand("Result", Type.GetType("System.Int64"));<br />
        oprResult.Value = (long)this.Value % (long)((Operand)rhs).Value;<br />
        return oprResult;<br />
    }<br />
<br />
    /// IComparisonOperators methods. Return values are always BooleanOperands type<br />
    public IOperand EqualTo(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.== : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = (long)this.Value == (long)((Operand)rhs).Value;<br />
        return oprResult;<br />
    }<br />
    public IOperand NotEqualTo(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.!= : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = ((long)this.Value != (long)((Operand)rhs).Value) ? true : false;<br />
        return oprResult;<br />
    }<br />
    public IOperand LessThan(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.< : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = ((long)this.Value < (long)((Operand)rhs).Value) ? true : false;<br />
        return oprResult;<br />
    }<br />
    public IOperand LessThanOrEqualTo(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.<= : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = ((long)this.Value <= (long)((Operand)rhs).Value) ? true : false;<br />
        return oprResult;<br />
    }<br />
    public IOperand GreaterThan(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.> : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = ((long)this.Value > (long)((Operand)rhs).Value) ? true : false;<br />
        return oprResult;<br />
    }<br />
    public IOperand GreaterThanOrEqualTo(IOperand rhs)<br />
    {<br />
        if (!(rhs is LongOperand))<br />
            throw new RPN_Exception("Argument invalid in LongOperand.>= : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = ((long)this.Value >= (long)((Operand)rhs).Value) ? true : false;<br />
        return oprResult;<br />
    }<br />
}<br />
///<br />
/// Operand corresponding to Boolean Type<br />
///<br />
public class BoolOperand : Operand, ILogicalOperations<br />
{<br />
    public BoolOperand(string szVarName, object varValue)<br />
        : base(szVarName, varValue)<br />
    {<br />
    }<br />
    public BoolOperand(string szVarName)<br />
        : base(szVarName)<br />
    {<br />
    }<br />
    public override string ToString()<br />
    {<br />
        return this.Value.ToString();<br />
    }<br />
    public override void ExtractAndSetValue(string szValue, bool bFormula)<br />
    {<br />
        m_VarValue = !bFormula ? Convert.ToBoolean(szValue) : false;<br />
    }<br />
    public IOperand AND(IOperand rhs)<br />
    {<br />
        if (!(rhs is BoolOperand))<br />
            throw new RPN_Exception("Argument invalid in BoolOperand.&& : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = ((bool)this.Value && (bool)((Operand)rhs).Value) ? true : false;<br />
        return oprResult;<br />
    }<br />
    public IOperand OR(IOperand rhs)<br />
    {<br />
        if (!(rhs is BoolOperand))<br />
            throw new RPN_Exception("Argument invalid in BoolOperand.|| : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = ((bool)this.Value || (bool)((Operand)rhs).Value) ? true : false;<br />
        return oprResult;<br />
    }<br />
}<br />
<br />
public class OperandHelper<br />
{<br />
    ///<br />
    /// Factory method to create corresponding Operands.<br />
    /// Extended this method to create newer datatypes.<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    static public Operand CreateOperand(string szVarName, Type varType, object varValue)<br />
    {<br />
        Operand oprResult = null;<br />
        switch (varType.ToString())<br />
        {<br />
            case "System.Int32":<br />
            case "System.Int64":<br />
                oprResult = new LongOperand(szVarName, varValue);<br />
                return oprResult;<br />
            //break;<br />
            //case System.Decimal:<br />
            //case System.Single:<br />
            // oprResult = new DecimalOperand( szVarName, varValue );<br />
            // return oprResult;<br />
            // break;<br />
            case "System.String":<br />
                oprResult = new StringOperand(szVarName, varValue);<br />
                return oprResult;<br />
            //break;<br />
<br />
<br />
<br />
<br />
        }<br />
        throw new RPN_Exception("Unhandled type : " + varType.ToString());<br />
    }<br />
    static public Operand CreateOperand(string szVarName, Type varType)<br />
    {<br />
        return OperandHelper.CreateOperand(szVarName, varType, null);<br />
    }<br />
}<br />
public class StringOperand : Operand, IComparisonOperations<br />
{<br />
    public StringOperand(string szVarName, object varValue)<br />
        : base(szVarName, varValue)<br />
    {<br />
    }<br />
    public StringOperand(string szVarName)<br />
        : base(szVarName)<br />
    {<br />
    }<br />
    public override string ToString()<br />
    {<br />
        return m_szVarName;<br />
    }<br />
    public override void ExtractAndSetValue(string szValue, bool bFormula)<br />
    {<br />
        m_VarValue = !bFormula ? Convert.ToString(szValue) : "";<br />
    }<br />
    /// IComparisonOperators methods. Return values are always BooleanOperands type<br />
    public IOperand EqualTo(IOperand rhs)<br />
    {<br />
        if (!(rhs is StringOperand))<br />
            throw new RPN_Exception("Argument invalid in StringOperand.== : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = (string)this.Value == (string)((Operand)rhs).Value;<br />
        return oprResult;<br />
    }<br />
    public IOperand NotEqualTo(IOperand rhs)<br />
    {<br />
        if (!(rhs is StringOperand))<br />
            throw new RPN_Exception("Argument invalid in StringOperand.!= : rhs");<br />
        BoolOperand oprResult = new BoolOperand("Result");<br />
        oprResult.Value = ((string)this.Value != (string)((Operand)rhs).Value) ? true : false;<br />
        return oprResult;<br />
    }<br />
    public IOperand LessThan(IOperand rhs)<br />
    {<br />
        // if( !(rhs is StringOperand) )<br />
        throw new RPN_Exception("LessThan operator is invalid for string");<br />
        // BoolOperand oprResult = new BoolOperand("Result");<br />
        // oprResult.Value = ((string)this.Value < (string)((Operand)rhs).Value) ? true : false;<br />
        // return oprResult;<br />
    }<br />
    public IOperand LessThanOrEqualTo(IOperand rhs)<br />
    {<br />
        // if( !(rhs is StringOperand) )<br />
        throw new RPN_Exception("LessThanOrEqualTo operator is invalid for string");<br />
        // BoolOperand oprResult = new BoolOperand("Result");<br />
        // oprResult.Value = ((string)this.Value <= (string)((Operand)rhs).Value) ? true : false;<br />
        // return oprResult;<br />
    }<br />
    public IOperand GreaterThan(IOperand rhs)<br />
    {<br />
        // if( !(rhs is StringOperand) )<br />
        throw new RPN_Exception("GreaterThan operator is invalid for string");<br />
        // BoolOperand oprResult = new BoolOperand("Result");<br />
        // oprResult.Value = ((string)this.Value > (string)((Operand)rhs).Value) ? true : false;<br />
        // return oprResult;<br />
    }<br />
    public IOperand GreaterThanOrEqualTo(IOperand rhs)<br />
    {<br />
        // if( !(rhs is StringOperand) )<br />
        throw new RPN_Exception("GreaterThanOrEqualTo operator is invalid for string");<br />
        // BoolOperand oprResult = new BoolOperand("Result");<br />
        // oprResult.Value = ((string)this.Value >= (string)((Operand)rhs).Value) ? true : false;<br />
        // return oprResult;<br />
    }<br />
}<br />
#endregion<br />
<br />
#region Operators<br />
///<br />
/// Base class of all operators. Provides datastorage<br />
///<br />
public abstract class Operator : IOperator<br />
{<br />
    public Operator(char cOperator)<br />
    {<br />
        m_szOperator = new String(cOperator, 1);<br />
    }<br />
    public Operator(string szOperator)<br />
    {<br />
        m_szOperator = szOperator;<br />
    }<br />
    public override string ToString()<br />
    {<br />
        return m_szOperator;<br />
    }<br />
    public abstract IOperand Eval(IOperand lhs, IOperand rhs);<br />
    public abstract IOperand Eval(IOperand lhs);<br />
    public string Value<br />
    {<br />
        get<br />
        {<br />
            return m_szOperator;<br />
        }<br />
        set<br />
        {<br />
            m_szOperator = value;<br />
        }<br />
    }<br />
    protected string m_szOperator = "";<br />
}<br />
///<br />
/// Arithmetic Operator Class providing evaluation services for "+-/*%" operators.<br />
///<br />
public class ArithmeticOperator : Operator<br />
{<br />
    public ArithmeticOperator(char cOperator)<br />
        : base(cOperator)<br />
    {<br />
    }<br />
    public ArithmeticOperator(string szOperator)<br />
        : base(szOperator)<br />
    {<br />
    }<br />
    //bool bBinaryOperator = true;<br />
<br />
    public override IOperand Eval(IOperand lhs, IOperand rhs)<br />
    {<br />
        if (!(lhs is IArithmeticOperations))<br />
            throw new RPN_Exception("Argument invalid in ArithmeticOperator.Eval - Invalid Expression : lhs");<br />
        switch (m_szOperator)<br />
        {<br />
            case "+":<br />
                return ((IArithmeticOperations)lhs).Plus(rhs);<br />
            case "-":<br />
                return ((IArithmeticOperations)lhs).Minus(rhs);<br />
            case "*":<br />
                return ((IArithmeticOperations)lhs).Multiply(rhs);<br />
            case "/":<br />
                return ((IArithmeticOperations)lhs).Divide(rhs);<br />
            case "%":<br />
                return ((IArithmeticOperations)lhs).Modulo(rhs);<br />
        }<br />
        throw new RPN_Exception("Unsupported Arithmetic operation " + m_szOperator);<br />
    }<br />
<br />
    public override IOperand Eval(IOperand lhs)<br />
    {<br />
        if (!(lhs is IArithmeticOperations))<br />
            throw new RPN_Exception("Argument invalid in ArithmeticOperator.Eval - Invalid Expression : lhs");<br />
        switch (m_szOperator)<br />
        {<br />
            case "~":<br />
                return ((IArithmeticOperations)lhs).Negate();<br />
        }<br />
        throw new RPN_Exception("Unsupported Arithmetic operation " + m_szOperator);<br />
    }<br />
}<br />
///<br />
/// Comparison Operator Class providing evaluation services for "==", "!=","<", "<=", ">", ">=" operators.<br />
///<br />
public class ComparisonOperator : Operator<br />
{<br />
    public ComparisonOperator(char cOperator)<br />
        : base(cOperator)<br />
    {<br />
    }<br />
    public ComparisonOperator(string szOperator)<br />
        : base(szOperator)<br />
    {<br />
    }<br />
    //bool bBinaryOperator = true;<br />
<br />
    public override IOperand Eval(IOperand lhs) { return null; }<br />
<br />
    //{"==", "!=","<", "<=", ">", ">="}<br />
    public override IOperand Eval(IOperand lhs, IOperand rhs)<br />
    {<br />
        if (!(lhs is IComparisonOperations))<br />
            throw new RPN_Exception("Argument invalid in ComparisonOperator.Eval - Invalid Expression : lhs");<br />
        switch (m_szOperator)<br />
        {<br />
            case "==":<br />
                return ((IComparisonOperations)lhs).EqualTo(rhs);<br />
            case "!=":<br />
                return ((IComparisonOperations)lhs).NotEqualTo(rhs);<br />
            case "<":<br />
                return ((IComparisonOperations)lhs).LessThan(rhs);<br />
            case "<=":<br />
                return ((IComparisonOperations)lhs).LessThanOrEqualTo(rhs);<br />
            case ">":<br />
                return ((IComparisonOperations)lhs).GreaterThan(rhs);<br />
            case ">=":<br />
                return ((IComparisonOperations)lhs).GreaterThanOrEqualTo(rhs);<br />
        }<br />
        throw new RPN_Exception("Unsupported Comparison operation " + m_szOperator);<br />
    }<br />
}<br />
<br />
///<br />
/// Logical Operator Class providing evaluation services for && and || operators.<br />
///<br />
public class LogicalOperator : Operator<br />
{<br />
    public LogicalOperator(char cOperator)<br />
        : base(cOperator)<br />
    {<br />
    }<br />
    public LogicalOperator(string szOperator)<br />
        : base(szOperator)<br />
    {<br />
    }<br />
    //bool bBinaryOperator = true;<br />
<br />
    public override IOperand Eval(IOperand lhs) { return null; }<br />
<br />
    //{"&&", "||"}<br />
    public override IOperand Eval(IOperand lhs, IOperand rhs)<br />
    {<br />
        if (!(lhs is ILogicalOperations))<br />
            throw new RPN_Exception("Argument invalid in LogicalOperator.Eval - Invalid Expression : lhs");<br />
        switch (m_szOperator)<br />
        {<br />
            case "&&":<br />
                return ((ILogicalOperations)lhs).AND(rhs);<br />
            case "||":<br />
                return ((ILogicalOperations)lhs).OR(rhs);<br />
        }<br />
        throw new RPN_Exception("Unsupported Logical operation " + m_szOperator);<br />
    }<br />
}<br />
<br />
public class OperatorHelper<br />
{<br />
    ///<br />
    /// Factory method to create Operator objects.<br />
    ///<br />
    ///<br />
    ///<br />
    static public IOperator CreateOperator(string szOperator)<br />
    {<br />
        IOperator oprtr = null;<br />
        if (OperatorHelper.IsArithmeticOperator(szOperator))<br />
        {<br />
            oprtr = new ArithmeticOperator(szOperator);<br />
            return oprtr;<br />
        }<br />
        if (OperatorHelper.IsComparisonOperator(szOperator))<br />
        {<br />
            oprtr = new ComparisonOperator(szOperator);<br />
            return oprtr;<br />
        }<br />
        if (OperatorHelper.IsLogicalOperator(szOperator))<br />
        {<br />
            oprtr = new LogicalOperator(szOperator);<br />
            return oprtr;<br />
        }<br />
        throw new RPN_Exception("Unhandled Operator : " + szOperator);<br />
    }<br />
    static public IOperator CreateOperator(char cOperator)<br />
    {<br />
        return CreateOperator(new string(cOperator, 1));<br />
    }<br />
    /// Some helper functions.<br />
    public static bool IsOperator(string currentOp)<br />
    {<br />
        int nPos = Array.IndexOf(m_AllOps, currentOp.Trim());<br />
        if (nPos != -1)<br />
            return true;<br />
        else<br />
            return false;<br />
    }<br />
    public static bool IsUnaryOperator(string currentOp)<br />
    {<br />
        int nPos = Array.IndexOf(m_AllUnaryOps, currentOp.Trim());<br />
        if (nPos != -1)<br />
            return true;<br />
        else<br />
            return false;<br />
    }<br />
    public static bool IsArithmeticOperator(string currentOp)<br />
    {<br />
        int nPos = Array.IndexOf(m_AllArithmeticOps, currentOp);<br />
        if (nPos != -1)<br />
            return true;<br />
        else<br />
            return false;<br />
    }<br />
    public static bool IsComparisonOperator(string currentOp)<br />
    {<br />
        int nPos = Array.IndexOf(m_AllComparisonOps, currentOp);<br />
        if (nPos != -1)<br />
            return true;<br />
        else<br />
            return false;<br />
    }<br />
    public static bool IsLogicalOperator(string currentOp)<br />
    {<br />
        int nPos = Array.IndexOf(m_AllLogicalOps, currentOp);<br />
        if (nPos != -1)<br />
            return true;<br />
        else<br />
            return false;<br />
    }<br />
    #region Precedence<br />
    /// Precedence is determined by relative indices of the operators defined in<br />
    /// in m_AllOps variable<br />
<br />
    ///<br />
    /// Summary of IsLowerPrecOperator.<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    public static bool IsLowerPrecOperator(string currentOp, string prevOp)<br />
    {<br />
        int nCurrIdx;<br />
        int nPrevIdx;<br />
        GetCurrentAndPreviousIndex(m_AllOps, currentOp, prevOp, out nCurrIdx, out nPrevIdx);<br />
        if (nCurrIdx < nPrevIdx)<br />
        {<br />
            return true;<br />
        }<br />
        return false;<br />
    }<br />
<br />
    ///<br />
    /// Summary of IsHigherPrecOperator.<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    public static bool IsHigherPrecOperator(string currentOp, string prevOp)<br />
    {<br />
        int nCurrIdx;<br />
        int nPrevIdx;<br />
        GetCurrentAndPreviousIndex(m_AllOps, currentOp, prevOp, out nCurrIdx, out nPrevIdx);<br />
        if (nCurrIdx > nPrevIdx)<br />
        {<br />
            return true;<br />
        }<br />
        return false;<br />
    }<br />
<br />
    ///<br />
    /// Summary of IsEqualPrecOperator.<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    public static bool IsEqualPrecOperator(string currentOp, string prevOp)<br />
    {<br />
        int nCurrIdx;<br />
        int nPrevIdx;<br />
        GetCurrentAndPreviousIndex(m_AllOps, currentOp, prevOp, out nCurrIdx, out nPrevIdx);<br />
        if (nCurrIdx == nPrevIdx)<br />
        {<br />
            return true;<br />
        }<br />
        return false;<br />
    }<br />
    ///<br />
    /// Summary of GetCurrentAndPreviousIndex.<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    ///<br />
    private static void GetCurrentAndPreviousIndex(string[] allOps, string currentOp, string prevOp,<br />
    out int nCurrIdx, out int nPrevIdx)<br />
    {<br />
        nCurrIdx = -1;<br />
        nPrevIdx = -1;<br />
        for (int nIdx = 0; nIdx < allOps.Length; nIdx++)<br />
        {<br />
            if (allOps[nIdx] == currentOp)<br />
            {<br />
                nCurrIdx = nIdx;<br />
            }<br />
            if (allOps[nIdx] == prevOp)<br />
            {<br />
                nPrevIdx = nIdx;<br />
            }<br />
            if (nPrevIdx != -1 && nCurrIdx != -1)<br />
            {<br />
                break;<br />
            }<br />
        }<br />
        if (nCurrIdx == -1)<br />
        {<br />
            throw new RPN_Exception("Unknown operator - " + currentOp);<br />
        }<br />
        if (nPrevIdx == -1)<br />
        {<br />
            throw new RPN_Exception("Unknown operator - " + prevOp);<br />
        }<br />
<br />
    }<br />
    #endregion<br />
    #region RegEx<br />
    ///<br />
    /// This gets the regular expression used to find operators in the input<br />
    /// expression.<br />
    ///<br />
    ///<br />
    ///<br />
    static public string GetOperatorsRegEx(ExpressionType exType)<br />
    {<br />
        StringBuilder strRegex = new StringBuilder();<br />
        if ((exType & ExpressionType.ET_ARITHMETIC).Equals(ExpressionType.ET_ARITHMETIC))<br />
        {<br />
            if (strRegex.Length == 0)<br />
            {<br />
                strRegex.Append(m_szArthmtcRegEx);<br />
            }<br />
            else<br />
            {<br />
                strRegex.Append("|" + m_szArthmtcRegEx);<br />
            }<br />
        }<br />
        if ((exType & ExpressionType.ET_COMPARISON).Equals(ExpressionType.ET_COMPARISON))<br />
        {<br />
            if (strRegex.Length == 0)<br />
            {<br />
                strRegex.Append(m_szCmprsnRegEx);<br />
            }<br />
            else<br />
            {<br />
                strRegex.Append("|" + m_szCmprsnRegEx);<br />
            }<br />
        }<br />
        if ((exType & ExpressionType.ET_LOGICAL).Equals(ExpressionType.ET_LOGICAL))<br />
        {<br />
            if (strRegex.Length == 0)<br />
            {<br />
                strRegex.Append(m_szLgclRegEx);<br />
            }<br />
            else<br />
            {<br />
                strRegex.Append("|" + m_szLgclRegEx);<br />
            }<br />
        }<br />
        if (strRegex.Length == 0)<br />
            throw new RPN_Exception("Invalid combination of ExpressionType value");<br />
        return "(" + strRegex.ToString() + ")";<br />
    }<br />
    ///<br />
    /// Expression to pattern match various operators<br />
    ///<br />
    static string m_szArthmtcRegEx = @"[+\-*/%()]{1}";<br />
    static string m_szCmprsnRegEx = @"[=<>!]{1,2}";<br />
    static string m_szLgclRegEx = @"[&|]{2}";<br />
    static string m_szUnaryRegEx = @"[~]{1}";<br />
    #endregion<br />
<br />
    public static string[] AllOperators<br />
    {<br />
        get<br />
        {<br />
            return m_AllOps;<br />
        }<br />
    }<br />
<br />
    ///<br />
    /// All Operators supported by this module currently.<br />
    /// Modify here to add more operators IN ACCORDANCE WITH their precedence.<br />
    /// Additionally add into individual variables to support some helper methods above.<br />
    ///<br />
    static string[] m_AllOps = { "||", "&&", "|", "^", "&", "==", "!=",<br />
"<", "<=", ">", ">=", "+", "-", "*", "/", "~", "%", "(", ")" };<br />
    static string[] m_AllArithmeticOps = { "+", "-", "~", "*", "/", "%" };<br />
    static string[] m_AllComparisonOps = { "==", "!=", "<", "<=", ">", ">=" };<br />
    static string[] m_AllLogicalOps = { "&&", "||" };<br />
    static string[] m_AllUnaryOps = { "~" };<br />
}<br />
<br />
#endregion<br />
<br />
#region TODO List<br />
/// TODO: Support for unary operators<br />
/// Added support for unary ops 5/5/2006, stuallen<br />
/// TODO: Support for bitwise & and |<br />
/// TODO: how to handle a combo expression with multiple braces as a logical/comparison expression?<br />
/// e.g. ((2+3)*2<10 || 1!=1) && 2*2==4 as a logical expression?<br />
/// TODO: Form to accept values for formulae<br />
#endregion<br />
// Function to test for Positive Integers.<br />
#region Content check<br />
public class StringContentCheck<br />
{<br />
    static public bool IsNaturalNumber(String strNumber)<br />
    {<br />
        Regex objNotNaturalPattern = new Regex("[^0-9]");<br />
        Regex objNaturalPattern = new Regex("0*[1-9][0-9]*");<br />
        return !objNotNaturalPattern.IsMatch(strNumber) &&<br />
        objNaturalPattern.IsMatch(strNumber);<br />
    }<br />
<br />
    // Function to test for Positive Integers with zero inclusive<br />
<br />
    static public bool IsWholeNumber(String strNumber)<br />
    {<br />
        Regex objNotWholePattern = new Regex("[^0-9]");<br />
        return !objNotWholePattern.IsMatch(strNumber);<br />
    }<br />
<br />
    // Function to Test for Integers both Positive & Negative<br />
<br />
    static public bool IsInteger(String strNumber)<br />
    {<br />
        Regex objNotIntPattern = new Regex("[^0-9-]");<br />
        Regex objIntPattern = new Regex("^-[0-9]+$|^[0-9]+$");<br />
        return !objNotIntPattern.IsMatch(strNumber) && objIntPattern.IsMatch(strNumber);<br />
    }<br />
<br />
    // Function to Test for Positive Number both Integer & Real<br />
<br />
    static public bool IsPositiveNumber(String strNumber)<br />
    {<br />
        Regex objNotPositivePattern = new Regex("[^0-9.]");<br />
        Regex objPositivePattern = new Regex("^[.][0-9]+$|[0-9]*[.]*[0-9]+$");<br />
        Regex objTwoDotPattern = new Regex("[0-9]*[.][0-9]*[.][0-9]*");<br />
        return !objNotPositivePattern.IsMatch(strNumber) &&<br />
        objPositivePattern.IsMatch(strNumber) &&<br />
        !objTwoDotPattern.IsMatch(strNumber);<br />
    }<br />
<br />
    // Function to test whether the string is valid number or not<br />
    static public bool IsNumber(String strNumber)<br />
    {<br />
        Regex objNotNumberPattern = new Regex("[^0-9.-]");<br />
        Regex objTwoDotPattern = new Regex("[0-9]*[.][0-9]*[.][0-9]*");<br />
        Regex objTwoMinusPattern = new Regex("[0-9]*[-][0-9]*[-][0-9]*");<br />
        String strValidRealPattern = "^([-]|[.]|[-.]|[0-9])[0-9]*[.]*[0-9]+$";<br />
        String strValidIntegerPattern = "^([-]|[0-9])[0-9]*$";<br />
        Regex objNumberPattern = new Regex("(" + strValidRealPattern + ")|(" + strValidIntegerPattern + ")");<br />
        return !objNotNumberPattern.IsMatch(strNumber) &&<br />
        !objTwoDotPattern.IsMatch(strNumber) &&<br />
        !objTwoMinusPattern.IsMatch(strNumber) &&<br />
        objNumberPattern.IsMatch(strNumber);<br />
    }<br />
<br />
    // Function To test for Alphabets.<br />
<br />
    static public bool IsAlpha(String strToCheck)<br />
    {<br />
        Regex objAlphaPattern = new Regex("[^a-zA-Z ]");<br />
        return !objAlphaPattern.IsMatch(strToCheck);<br />
    }<br />
    // Function to Check for AlphaNumeric.<br />
    static public bool IsAlphaNumeric(String strToCheck)<br />
    {<br />
        Regex objAlphaNumericPattern = new Regex("[^a-zA-Z0-9 ]");<br />
        return !objAlphaNumericPattern.IsMatch(strToCheck);<br />
    }<br />
}<br />
#endregion

GeneralBug Pin
Ihor Bobak12-Feb-06 9:44
Ihor Bobak12-Feb-06 9:44 
GeneralRe: Bug Pin
stuallenii5-May-06 5:53
stuallenii5-May-06 5:53 
GeneralSome changes for String comparing.... Pin
neuralc10-Nov-04 5:31
neuralc10-Nov-04 5:31 
GeneralRe: Some changes for String comparing.... Pin
zitun15-May-06 1:51
zitun15-May-06 1:51 
GeneralUPDATE : Some changes for String comparing.... Pin
zitun30-May-06 0:08
zitun30-May-06 0:08 
GeneralDecimal numbers Pin
Gian7-May-04 1:30
Gian7-May-04 1:30 
GeneralRe: Decimal numbers Pin
Ciprian Talaba22-Aug-06 23:43
Ciprian Talaba22-Aug-06 23:43 
GeneralRe: Decimal numbers Pin
asmgx16-May-07 16:22
asmgx16-May-07 16:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.