当前位置:编程学习 > C#/ASP.NET >>

从C#转换过来的表达式解析器,求大神是否能支持中文混合。

Public Class Calculator
    ''' <summary>最高运算级别常量</summary>
    Protected Const MAX_LEVEL As Integer = 99
    ''' <summary> ''' 获取运算符的级别 ''' </summary> ''' <param name="o"></param> ''' <returns></returns>
    Private Shared Function GetOperatorLevel(ByVal o As String) As Integer
        For i As Integer = 0 To Level.Length - 1
            If DirectCast(Level(i)(0), String) = o Then
                Return CInt(Level(i)(1))
            End If
        Next
        Return -1
    End Function

    ''' <summary> ''' 如果字符串是已运算符开头,则返回该运算符,否则返回null ''' </summary> ''' <param name="v">要检查的字符串</param> ''' <returns></returns> 

    Private Shared Function GetOperator(ByVal v As String) As String
        For i As Integer = 0 To Level.Length - 1
            If v.StartsWith(DirectCast(Level(i)(0), String)) Then
                Return DirectCast(Level(i)(0), String)
            End If
        Next
        Return Nothing
    End Function


#Region "运算符与支持的函数" '数学函数 '三角函数 '条件函数
    Private Shared Level As Object()() = New Object()() _
    { _
    New Object() {",", 0}, New Object() {"=", 1}, New Object() {">=", 1}, New Object() {"<=", 1}, New Object() {"<>", 1}, New Object() {">", 1}, New Object() {"<", 1}, New Object() {"+", 2}, New Object() {"-", 2}, New Object() {"*", 3}, New Object() {"/", 3}, New Object() {"%", 3}, New Object() {"NEG", 4}, New Object() {"^", 5}, _
    New Object() {"(", MAX_LEVEL}, _
    New Object() {"ROUND(", MAX_LEVEL}, _
    New Object() {"TRUNC(", MAX_LEVEL}, _
    New Object() {"MAX(", MAX_LEVEL}, _
    New Object() {"MIN(", MAX_LEVEL}, _
    New Object() {"ABS(", MAX_LEVEL}, _
    New Object() {"SUM(", MAX_LEVEL}, _
    New Object() {"AVERAGE(", MAX_LEVEL}, _
    New Object() {"SQRT(", MAX_LEVEL}, _
    New Object() {"EXP(", MAX_LEVEL}, _
    New Object() {"LOG(", MAX_LEVEL}, _
    New Object() {"LOG10(", MAX_LEVEL}, _
    New Object() {"SIN(", MAX_LEVEL}, _
    New Object() {"COS(", MAX_LEVEL}, _
    New Object() {"TAN(", MAX_LEVEL}, _
    New Object() {"IF(", MAX_LEVEL}, _
    New Object() {"NOT(", MAX_LEVEL}, _
    New Object() {"AND(", MAX_LEVEL}, _
    New Object() {"OR(", MAX_LEVEL} _
    }
#End Region


#Region "解析表达式"
    ''' <summary>运算符</summary>
    Private _opt As String = Nothing
    '''  <summary>运算符右边的表达式</summary> 
    Private _expression As String = Nothing
    ''' <summary>运算符左边的值</summary>
    Private _leftValue As String
    Public Shared Function CalculateExpression(ByVal expression As String, ByVal dataProvider As Specialized.NameValueCollection) As Decimal()
        Dim calc As New Calculator(expression, dataProvider)
        Dim r As Decimal() = calc.Calculate()
        Return r
    End Function
    Private _data As Specialized.NameValueCollection
    Public Sub New(ByVal expression As String, ByVal dataProvider As Specialized.NameValueCollection)
        _data = dataProvider
        _expression = expression.ToUpper()
        If GetIndex(_expression) <> -1 Then
            Throw New Exception("缺少""(""")
        End If
        Initialize()
    End Sub
    ''' <summary>初始化对象(将表达式拆分为左边的值、运算符和右边的表达式)</summary>
    Private Sub Initialize()
        Dim right As String
        GetNext(_expression, _leftValue, _opt, right)
        _expression = right
    End Sub
    ''' <summary> ''' 拆分表达式 ''' </summary> ''' <param name="expression">表达式</param> ''' <param name="left">左边的值</param> ''' <param name="opt">运算符</param> ''' <param name="right">右边的值</param>
    Private Sub GetNext(ByVal expression As String, ByRef left As String, ByRef opt As String, ByRef right As String)
        right = expression
        left = String.Empty
        opt = Nothing
        While right <> String.Empty
            opt = GetOperator(right)
            If opt IsNot Nothing Then
                right = right.Substring(opt.Length, right.Length - opt.Length)
                Exit While
            Else : left += right(0)
                right = right.Substring(1, right.Length - 1)
            End If
        End While
        right = right.Trim()
    End Sub
    ''' <summary>计算表达式</summary> ''' <returns>返回值(可能有多个,如逗号表达式会返回多个值)</returns>
    Public Function Calculate() As Decimal()
        '如果运算符为空,则直接返回左边的值
        If _opt Is Nothing Then
            Dim r As Decimal = Decimal.Zero
            Try
                r = Decimal.Parse(_leftValue)
            Catch
                Try
                    r = Decimal.Parse(_data(_leftValue))
                Catch
                    Throw New Exception("错误的格式:" & _leftValue)
                End Try
            End Try
            Return New Decimal(0) {r}
        End If
        '判断是否是最高优先级的运算符(括号和函数)
        If GetOperatorLevel(_opt) <> MAX_LEVEL Then
            '四则运算符中,只有当-左边无值的时候是单目运算
            If _opt <> "-" AndAlso _leftValue = String.Empty Then
                Throw New Exception("""" & _opt & """运算符的左边需要值或表达式")
            End If
            If _opt = "-" AndAlso _leftValue = String.Empty Then
                _opt = "NEG"
            End If
            If _expression = String.Empty Then
                Throw New Exception("""" & _opt & """运算符的右边需要值或表达式")
            End If
            Return CalculateTwoParms()
        Else   '括号和函数左边都不需要值
            If _leftValue <> String.Empty Then
                Throw New Exception("""" & _opt & """运算符的左边不需要值或表达式")
            End If
            Return CalculateFunction()
        End If
    End Function
    ''' <summary>计算函数(括号运算符被当作函数计算,所有的函数必须已右括号结尾)</summary>
    Private Function CalculateFunction() As Decimal()
        '查找对应的右括号
        Dim inx As Integer = GetIndex(_expression)
        If inx = -1 Then
            Throw New Exception("缺少')'")
        End If
        Dim l As String = _expression.Substring(0, inx)
        '如果表达式已经完成,则返回计算结果,否则计算当前结果
        '并修改左值、运算符、右边表达式的值,然后调用Calculate继续运算
        If inx = _expression.Length - 1 Then
            Return Calc(_opt, l)
        Else
            Dim left As String, right As String, op As String
            _expression = _expression.Substring(inx + 1, _expression.Length - inx - 1)
            GetNext(_expression, left, op, right)
            Dim r As Decimal() = Calc(_opt, l)
            _leftValue = r(r.Length - 1).ToString()
            If op Is Nothing Then
                Throw New Exception("')'运算符的右边需要运算符")
            End If
            _opt = op
            _expression = right
            Return Calculate()
        End If
    End Function
    ''' <summary> ''' 获取第一个未封闭的右括号在字符串中的位置 ''' </summary>
    ''' <param name="expression">传入的字符串</param>
    Private Function GetIndex(ByVal expression As String) As Integer
        Dim count As Integer = 0
        For i As Integer = 0 To expression.Length - 1
            If expression(i) = ")" Then
                If count = 0 Then
                    Return i
                Else
                    count -= 1
                End If
            End If
            If expression(i) = "(" Then
                count += 1
            End If
        Next
        Return -1
    End Function
    ''' <summary>计算四则表达式</summary>
    Private Function CalculateTwoParms() As Decimal()
        Dim left As String, right As String, op As String
        GetNext(_expression, left, op, right)
        Dim result As Decimal(), r As Decimal()
        '如果下一个运算符的级别不大于当前运算符,则计算当前的值
        If op Is Nothing OrElse (GetOperatorLevel(_opt) >= GetOperatorLevel(op)) Then
            r = Calc(_opt, _leftValue, left)
        Else
            '如果下一个运算符的级别大于当前运算符
            Dim ex As String = left
            '则一直找到低于当前运算符级别的运算符,然后将该运算符和当前运算符中间的表达式   '提取出来,新构造一个对象,运算中            间级别高的表达式的值()
            '然后将新对爱的结果当作右边的值于当前的左值以及运算符进行运算
            While (GetOperatorLevel(_opt) < GetOperatorLevel(op) AndAlso right <> String.Empty)
                ex += op
                If GetOperatorLevel(op) = MAX_LEVEL Then
                    Dim pos As Integer = GetIndex(right)
                    ex += right.Substring(0, pos + 1)
                    right = right.Substring(pos + 1)
                End If
                GetNext(right, left, op, right)
                ex += left
            End While
            Dim calc__1 As New Calculator(ex, _data)
            Dim rl As Decimal() = calc__1.Calculate()
            r = Calc(_opt, _leftValue, rl(rl.Length - 1).ToString())
        End If
        '将上一步计算出来的结果作为当前的左值,然后将表达式剩下的部分作为当前的右边的表达式  '然后将下一个运算符作为当前运        算符, 然后递归运算
        _leftValue = r(r.Length - 1).ToString()
        _opt = op
        _expression = right
        Dim rr As Decimal() = Calculate()
        result = New Decimal(r.Length - 1 + (rr.Length - 1)) {}
        For i As Integer = 0 To r.Length - 2
            result(i) = r(i)
        Next
        For i As Integer = 0 To rr.Length - 1
            result(r.Length - 1 + i) = rr(i)
        Next
        Return result
    End Function
#End Region

从C#转换过来的表达式解析器 --------------------编程问答-------------------- #Region "运算"
    Private Function Calc(ByVal opt As String, ByVal expression As String) As Decimal()
        Dim calc__1 As New Calculator(expression, _data)
        Dim values As Decimal() = calc__1.Calculate()
        Dim v As Decimal = values(values.Length - 1)
        Dim r As Decimal = Decimal.Zero
        Select Case _opt
            Case "("
                r = v
                Exit Select
            Case "Str("
                r = v
                Exit Select
            Case "ROUND("
                If values.Length > 2 Then
                    Throw New Exception("Round函数需要一个或两个参数!")
                End If
                If values.Length = 1 Then
                    r = Decimal.Round(v, 0)
                Else
                    r = Decimal.Round(values(0), CInt(Math.Truncate(values(1))))
                End If
                Exit Select
            Case "TRUNC("
                If values.Length > 1 Then
                    Throw New Exception("Trunc函数只需要一个参数!")
                End If
                r = Decimal.Truncate(v)
                Exit Select
            Case "MAX("
                If values.Length < 2 Then
                    Throw New Exception("Max函数至少需要两个参数!")
                End If
                r = values(0)
                For i As Integer = 1 To values.Length - 1
                    If values(i) > r Then
                        r = values(i)
                    End If
                Next
                Exit Select
            Case "MIN("
                If values.Length < 2 Then
                    Throw New Exception("Min函数至少需要两个参数!")
                End If
                r = values(0)
                For i As Integer = 1 To values.Length - 1
                    If values(i) < r Then
                        r = values(i)
                    End If
                Next
                Exit Select
            Case "ABS"
                If values.Length > 1 Then
                    Throw New Exception("Abs函数只需要一个参数!")
                End If
                r = Math.Abs(v)
                Exit Select
            Case "SUM("
                For Each d As Decimal In values
                    r += d
                Next
                Exit Select
            Case "AVERAGE("
                For Each d As Decimal In values
                    r += d
                Next
                r /= values.Length
                Exit Select
            Case "IF("
                If values.Length <> 3 Then
                    Throw New Exception("IF函数需要三个参数!")
                End If
                If GetBoolean(values(0)) Then
                    r = values(1)
                Else
                    r = values(2)
                End If
                Exit Select
            Case "NOT("
                If values.Length <> 1 Then
                    Throw New Exception("NOT函数需要一个参数!")
                End If
                If GetBoolean(values(0)) Then
                    r = 0
                Else
                    r = 1
                End If
                Exit Select
            Case "OR("
                If values.Length < 1 Then
                    Throw New Exception("OR函数至少需要两个参数!")
                End If
                For Each d As Decimal In values
                    If GetBoolean(d) Then
                        Return New Decimal(0) {1}
                    End If
                Next
                Exit Select
            Case "AND("
                If values.Length < 1 Then
                    Throw New Exception("AND函数至少需要两个参数!")
                End If
                For Each d As Decimal In values
                    If Not GetBoolean(d) Then
                        Return New Decimal(0) {Decimal.Zero}
                    End If
                Next
                r = 1
                Exit Select
            Case "SQRT("
                If values.Length <> 1 Then
                    Throw New Exception("SQRT函数需要一个参数!")
                End If
                r = CDec(Math.Sqrt(CDbl(v)))
                Exit Select
            Case "SIN("
                If values.Length <> 1 Then
                    Throw New Exception("Sin函数需要一个参数!")
                End If
                r = CDec(Math.Sin(CDbl(v)))
                Exit Select
            Case "COS("
                If values.Length <> 1 Then
                    Throw New Exception("Cos函数需要一个参数!")
                End If
                r = CDec(Math.Cos(CDbl(v)))
                Exit Select
            Case "TAN("
                If values.Length <> 1 Then
                    Throw New Exception("Tan函数需要一个参数!")
                End If
                r = CDec(Math.Tan(CDbl(v)))
                Exit Select
            Case "EXP("
                If values.Length <> 1 Then
                    Throw New Exception("Exp函数需要一个参数!")
                End If
                r = CDec(Math.Exp(CDbl(v)))
                Exit Select
            Case "LOG("
                If values.Length > 2 Then
                    Throw New Exception("Log函数需要一个或两个参数!")
                End If
                If values.Length = 1 Then
                    r = CDec(Math.Log(CDbl(v)))
                Else
                    r = CDec(Math.Log(CDbl(values(0)), CDbl(values(1))))
                End If
                Exit Select
            Case "LOG10("
                If values.Length <> 1 Then
                    Throw New Exception("Log10函数需要一个参数!")
                End If
                r = CDec(Math.Log10(CDbl(v)))
                Exit Select
        End Select
        Return New Decimal(0) {r}
    End Function
    Private Function GetBoolean(ByVal d As Decimal) As Boolean
        Return CInt(Math.Truncate(d)) = 1
    End Function
    Private Function Calc(ByVal opt As String, ByVal leftEx As String, ByVal rightEx As String) As Decimal()
        Dim r As Decimal = Decimal.Zero
        Dim left As Decimal = Decimal.Zero, right As Decimal
        Try
            left = Decimal.Parse(leftEx)
        Catch
            If opt <> "NEG" Then
                Try
                    left = Decimal.Parse(_data(leftEx))
                Catch
                    Throw New Exception("错误的格式:" & leftEx)
                End Try
            End If
        End Try
        Try
            right = Decimal.Parse(rightEx)
        Catch
            Try
                right = Decimal.Parse(_data(rightEx))
            Catch
                Throw New Exception("错误的格式:" & leftEx)
            End Try
        End Try
        Select Case _opt
            Case "NEG"
                r = Decimal.Negate(right)
                Exit Select
            Case "+"
                r = left + right
                Exit Select
            Case "-"
                r = left - right
                Exit Select
            Case "*"
                r = left * right
                Exit Select
            Case "/"
                r = left / right
                Exit Select
            Case "%"
                r = Decimal.Remainder(left, right)
                Exit Select
            Case "^"
                r = CDec(Math.Pow(CDbl(left), CDbl(right)))
                Exit Select
            Case ","
                Return New Decimal(1) {left, right}
            Case "="
                r = IIf(left = right, 1, 0)
                Exit Select
            Case "<>"
                r = IIf(left <> right, 1, 0)
                Exit Select
            Case "<"
                r = IIf(left < right, 1, 0)
                Exit Select
            Case ">"
                r = IIf(left > right, 1, 0)
                Exit Select
            Case ">="
                r = IIf(left >= right, 1, 0)
                Exit Select
            Case "<="
                r = IIf(left <= right, 1, 0)
                Exit Select
        End Select
        Return New Decimal(0) {r}
    End Function
#End Region
End Class --------------------编程问答-------------------- 这段代码能解析  IF(2>1,1,0)  这样的表达式。
但我们在应用中更需要的是能够像EXCEL 一样,解析  IF(3>2,"是","否")
更进一步我需要从表达式:  IF(3>2,"最高限额为:" +2000,0) 能获得结果: "最高限额为:2000"
补充:.NET技术 ,  VB.NET
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,