Imports System.Text Namespace Expression ''' ''' 字符算数表达式求和 ''' Public Class StringExpression ''' 精度 Private Shared _doublePrecision As Double = 0.000001 ''' ''' 替换占位符 ''' ''' 字符串表达式 ''' Public Shared Function UseMarkSymbolReplace(str As String) As String Dim destString As New StringBuilder str = str.Replace(" ", "") str = str.Replace(">>", "r") 'right move str = str.Replace("<<", "l") ' left move str = str.Replace("||", "o") 'or str = str.Replace("&&", "a") 'and str = str.Replace(">=", "g") 'greater equal str = str.Replace("<=", "s") 'small equal str = str.Replace("<>", "u") 'unequal str = str.Replace("!=", "u") 'unequal str = str.Replace("==", "e") 'equal For i As Integer = 0 To str.Length - 1 '替换负号 If i = 0 Then If str.Chars(i) = "-"c Then destString.Append("0"c) End If destString.Append(str.Chars(i)) ElseIf str.Chars(i) = "-"c AndAlso str.Chars(i - 1) = "("c Then destString.Append("0"c) destString.Append(str.Chars(i)) Else destString.Append(str.Chars(i)) End If Next Return destString.ToString() End Function ''' ''' 替换表达式式中的十六进制占位符为实际内容,例如替换B4为buf中的第4位即buf(4)的值 ''' ''' ''' ''' Public Shared Function ReplaceBytes(buf() As Byte, expressionString As String) As String Dim ch As Char Dim count As Integer = 0 Dim str As String = "" Dim tmp As Integer For i As Integer = 0 To expressionString.Length - 1 If expressionString.Chars(i) = "B"c Then ch = expressionString.Chars(i + count + 1) While IsNumeric(ch) count += 1 If i + count + 1 >= expressionString.Length Then Exit While ch = expressionString.Chars(i + count + 1) End While If count <= 0 Then Return "" Dim st As String = Mid(expressionString, i + 1 + 1, count) tmp = Convert.ToInt32(st) If tmp > buf.Length - 1 Then Return "" str += buf(tmp).ToString i += count count = 0 Else str += expressionString.Chars(i) End If Next Return str End Function ''' ''' 获取表达式转换后的结果是否为真,0、false、空字符为假,1,true为真, 其余为通过计算不为0判断真假 ''' ''' ''' Public Shared Function GetBooleanResult(exp As String) As Boolean If exp Is Nothing Then Return False If String.IsNullOrWhiteSpace(exp) Then Return False exp = exp.ToLower() If exp.Equals($"false") Then Return False If exp.Equals($"true") Then Return True exp = exp.Replace("false", "0"c) exp = exp.Replace("true", "1"c) Dim str As String = GetDoubleExpressionResult(exp).ToString() Console.WriteLine($"Result:{str}") Return Math.Abs(GetDoubleExpressionResult(exp) - 0) > _doublePrecision End Function ''' ''' 获取double类型运算式字符串后缀表达式 ''' ''' 字符串表达式 ''' Public Shared Function GetDoubleExpressionResult(str As String) As Double Dim isNum As Boolean Dim numStack As New Stack(Of Double) Dim operatorStack As New Stack(Of Char) Dim num1, num2 As Double Dim priority As Integer Dim ch As Char str = UseMarkSymbolReplace(str) For i As Integer = 0 To str.Length - 1 ch = str.Chars(i) If ch >= "0"c AndAlso ch <= "9"c Then '数字处理 Dim tmpStr As String = String.Empty Dim len As Integer = 1 tmpStr += ch isNum = True While isNum If i + len >= str.Length Then Exit While ch = str.Chars(i + len) If ch >= "0"c AndAlso ch <= "9"c Then tmpStr += ch len += 1 ElseIf ch = "."c Then tmpStr += ch len += 1 Else isNum = False End If End While numStack.Push(Double.Parse(tmpStr)) i += len - 1 ElseIf CheckCharValidity(ch) = 1 Then '运算符号 If operatorStack.Count = 0 Then operatorStack.Push(ch) Else priority = GetCharacterPriority(ch) '获取当前符号的优先级 While operatorStack.Count > 0 AndAlso GetCharacterPriority(operatorStack.Peek) < 11 AndAlso priority <= GetCharacterPriority(operatorStack.Peek) num1 = numStack.Pop num2 = numStack.Pop numStack.Push(GetDoubleResult(num2, num1, operatorStack.Pop)) End While If priority = 0 Then '为后半边括号 operatorStack.Pop() Else '为前半边括号 operatorStack.Push(ch) End If End If End If If i = str.Length - 1 Then priority = -1 While operatorStack.Count > 0 AndAlso GetCharacterPriority(operatorStack.Peek) < 11 AndAlso priority <= GetCharacterPriority(operatorStack.Peek) num1 = numStack.Pop num2 = numStack.Pop numStack.Push(GetDoubleResult(num2, num1, operatorStack.Pop)) End While End If Next Return Math.Round(numStack.Pop, 3) '计算保留小数位三位 End Function ''' ''' 获取小数类型运算结果 ''' ''' 浮点型数1 ''' 浮点型数2 ''' 运算符 ''' Public Shared Function GetDoubleResult(num1 As Double, num2 As Double, c As Char) As Double Dim result As Double Select Case c Case "*"c result = num1 * num2 Case "/"c If Math.Abs(num2 - 0) < _doublePrecision Then Throw New Exception($"除数为0执行失败") result = num1 / num2 Case "%"c result = num1 Mod num2 Case "+"c result = num1 + num2 Case "-"c result = num1 - num2 Case "l"c '左移 result = CInt(num1) << CInt(num2) Case "r"c '右移 result = CInt(num1) >> CInt(num2) Case "&"c result = CInt(num1) And CInt(num2) Case "^"c result = CInt(num1) Xor CInt(num2) Case "|"c result = CInt(num1) Or CInt(num2) Case ">"c '大于等于 result = CInt(IIf(num1 > num2, 1, 0)) Case "<"c '大于等于 result = CInt(IIf(num1 < num2, 1, 0)) Case "="c '等于 result = CInt(IIf(Math.Abs(num1 - num2) < _doublePrecision, 1, 0)) Case "g"c '大于等于 result = CInt(IIf(num1 >= num2, 1, 0)) Case "s"c '小于等于 result = CInt(IIf(num1 <= num2, 1, 0)) Case "u"c '不等于 result = CInt(IIf(Math.Abs(num1 - num2) > _doublePrecision, 1, 0)) Case "e"c '等于 result = CInt(IIf(Math.Abs(num1 - num2) < _doublePrecision, 1, 0)) Case "a"c '逻辑与 If num1 > 0 AndAlso num2 > 0 Then result = 1 Else result = 0 End If Case "o"c '逻辑或 If num1 > 0 OrElse num2 > 0 Then result = 1 Else result = 0 End If Case Else Throw New Exception($"未知的操作符:[{c}]") End Select Return result End Function ''' ''' 获取符号的优先级 ''' ''' 运算符号 ''' Private Shared Function GetCharacterPriority(c As Char) As Integer Dim intNum As Integer Select Case c Case "("c intNum = 11 Case "*"c, "/"c, "%"c intNum = 10 Case "+"c, "-"c intNum = 9 Case "l"c, "r"c intNum = 8 Case ">"c, "<"c, "b"c, "s"c intNum = 7 Case "="c, "u"c, "e"c intNum = 6 Case "&"c intNum = 5 Case "^"c intNum = 4 Case "|"c intNum = 3 Case "a"c intNum = 2 Case "o"c intNum = 1 Case ")"c intNum = 0 Case Else Throw New Exception($"未知的操作符:[{c}]") End Select Return intNum End Function ''' ''' 校验字符合法性,0为数字,1为运算符,-1为未使用的运算符 ''' ''' 需要校验的字符 ''' Private Shared Function CheckCharValidity(c As Char) As Integer Select Case c Case "1"c, "2"c, "3"c, "4"c, "5"c, "6"c, "7"c, "8"c, "9"c, "0"c Return 0 Case "+"c, "-"c, "*"c, "/"c, "%"c, "^"c, "|"c, "&"c, "("c, ")"c, "o"c, "a"c, "l"c, "r"c, "."c, "u"c, "g"c, "s"c, "<"c, ">"c, "="c, "e"c Return 1 Case Else Return -1 End Select End Function ''' ''' 校验运算式字符串合法性(todo:待进一步完善检测逻辑) ''' ''' 需要校验的字符串 ''' Public Shared Function CheckExpressionString(str As String) As Boolean str = str.Replace(" ", "") For i As Integer = 0 To str.Length - 1 If CheckCharValidity(str.Chars(i)) = -1 Then Return False End If Next Return True End Function '''' '''' 获取int类型运算式字符串后缀表达式 '''' '''' 字符串表达式 '''' 'Public Shared Function GetIntegerExpressionResult(str As String) As Integer ' Dim isNum As Boolean ' Dim numberStack As New Stack(Of Integer) ' Dim operatorStack As New Stack(Of Char) ' Dim num1, num2, priority As Integer ' str = UseMarkSymbolReplace(str, False) ' For Each c As Char In str ' If c >= "0"c AndAlso c <= "9"c Then ' If isNum Then ' Dim tmp As Integer = numberStack.Pop ' tmp = tmp * 10 + Integer.Parse(c.ToString) ' numberStack.Push(tmp) ' Else ' numberStack.Push(Integer.Parse(c.ToString)) ' isNum = True ' End If ' ElseIf CheckCharValidity(c) = 1 Then ' isNum = False ' If operatorStack.Count = 0 Then ' operatorStack.Push(c) ' Else ' priority = GetCharacterPriority(c) ' While operatorStack.Count > 0 AndAlso GetCharacterPriority(operatorStack.Peek) < 11 AndAlso priority <= GetCharacterPriority(operatorStack.Peek) ' num1 = numberStack.Pop ' num2 = numberStack.Pop ' numberStack.Push(GetIntegerResult(num2, num1, operatorStack.Pop)) ' End While ' If priority = 0 Then ' operatorStack.Pop() ' Else ' operatorStack.Push(c) ' End If ' End If ' End If ' If c = str.Chars(str.Length - 1) Then ' priority = GetCharacterPriority(c) ' While operatorStack.Count > 0 AndAlso GetCharacterPriority(operatorStack.Peek) < 11 AndAlso priority <= GetCharacterPriority(operatorStack.Peek) ' num1 = numberStack.Pop ' num2 = numberStack.Pop ' numberStack.Push(GetIntegerResult(num2, num1, operatorStack.Pop)) ' End While ' End If ' Next ' Return numberStack.Pop 'End Function '''' '''' 获取整形的运算结果 '''' '''' 整数1 '''' 整数2 '''' 运算符 '''' 预算结果 'Public Shared Function GetIntegerResult(num1 As Integer, num2 As Integer, c As Char) As Integer ' Dim result As Integer ' Select Case c ' Case "*"c ' result = num1 * num2 ' Case "/"c ' result = num1 \ num2 ' Case "%"c ' result = num1 Mod num2 ' Case "+"c ' result = num1 + num2 ' Case "-"c ' result = num1 - num2 ' Case "L"c ' result = num1 << num2 ' Case "R"c ' result = num1 >> num2 ' Case "&"c ' result = num1 And num2 ' Case "^"c ' result = num1 Xor num2 ' Case "|"c ' result = num1 Or num2 ' Case ">"c '大于等于 ' result = CInt(IIf(num1 > num2, 1, 0)) ' Case "<"c '大于等于 ' result = CInt(IIf(num1 < num2, 1, 0)) ' Case "="c '等于 ' result = CInt(IIf(num1 = num2, 1, 0)) ' Case "g"c '大于等于 ' result = CInt(IIf(num1 >= num2, 1, 0)) ' Case "l"c '小于等于 ' result = CInt(IIf(num1 <= num2, 1, 0)) ' Case "u"c '不等于 ' result = CInt(IIf(num1 <> num2, 1, 0)) ' Case "e"c '等于 ' result = CInt(IIf(num1 = num2, 1, 0)) ' Case "A"c ' If num1 > 0 AndAlso num2 > 0 Then ' result = 1 ' Else ' result = 0 ' End If ' Case "O"c ' If num1 > 0 OrElse num2 > 0 Then ' result = 1 ' Else ' result = 0 ' End If ' Case Else ' Throw New Exception($"未知的操作符:[{c}]") ' End Select ' Return result 'End Function ' Private Shared ReadOnly _operateList As New List(Of Char) From {"+"c, "*"c, "/"c, "%"c, "-"c, "^"c, "|"c, "&"c} 'Private Shared Function CheckDoubleResultChar(exp As String) As Boolean ' For i As Integer = 0 To exp.Length - 1 ' If exp.Chars(i) > "0"c AndAlso exp.Chars(i) < "9"c Then ' '有效数字 ' Continue For ' End If ' Select Case exp.Chars(i) ' Case "-"c ' '减运算符前不能为运算符 ' Case "+"c, "*"c, "/"c, "%"c ' '运算符前后位必须为数字 ' If i = 0 Then Return False '不能为开头 ' If i = exp.Length - 1 Then Return False '不能为结尾 ' ' If exp.Chars(i + 1) Then Return False'下一位不能 ' Case "!"c'是否应该支持 ' '按位操作前后须有数字 ' Case "^"c ' '按位操作前后须有数字 ' Case "|"c ' '按位操作前后须有数字 ' '逻辑操作前后须有数字 ' '确定是否为逻辑操作 ' Case "&"c ' '按位操作前后须有数字 ' '逻辑操作前后须有数字 ' '确定是否为逻辑操作 ' Case ">"c ' '判断逻辑符或是组合符号 ' Case "<"c ' '判断逻辑符或是组合符号 ' Case "="c ' '判断逻辑符或是组合符号 ' Case "."c ' '前后必为数字 ' Case "("c ' '括号必须匹配 ' Case ")"c ' '括号必须匹配 ' Case " "c ' '空格忽略 ' Case Else ' End Select ' Next ' Return False 'End Function ''' ''' 返回表达式的值 'Momo 2022-11-10 增加 、Momo 2023-12-15 错误时抛出错误而不是弹窗 ''' ''' Public Shared Function ExecuteLimit(ByVal strExpression As String, ByRef dblResult As String) As Boolean '检测有无需要计算的表达式 If String.IsNullOrWhiteSpace(strExpression) Then '’MsgBox(strExpression & " 是空白值或表达式,执行失败!") 'Throw New Exception(strExpression & " 是空白值或表达式,执行失败!") 'Momo 2023-12-15 错误时抛出错误而不是弹窗 Return False End If '检测表达式的有效性 If StringExpression.CheckExpressionString(strExpression) = False Then '’MsgBox(strExpression & " 是无效值或表达式,执行失败!") 'Throw New Exception(strExpression & " 是无效值或表达式,执行失败!") 'Momo 2023-12-15 错误时抛出错误而不是弹窗 Return False End If Try dblResult = StringExpression.GetDoubleExpressionResult(strExpression).ToString() Return True Catch ex As Exception '’MsgBox(strExpression & " 表达式计算失败,执行失败!") 'Throw New Exception(strExpression & " 表达式计算失败,执行失败!") 'Momo 2023-12-15 错误时抛出错误而不是弹窗 Return False End Try End Function End Class End Namespace