This repository has been archived on 2025-11-27. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
AUTS_OLD/UTS_Core/Expression/StringExpression.vb

539 lines
21 KiB
VB.net
Raw Normal View History

2024-03-11 16:32:52 +08:00
Imports System.Text
Namespace Expression
''' <summary>
''' 字符算数表达式求和
''' </summary>
Public Class StringExpression
''' <summary>精度</summary>
Private Shared _doublePrecision As Double = 0.000001
''' <summary>
''' 替换占位符
''' </summary>
''' <param name="str">字符串表达式</param>
''' <returns></returns>
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
''' <summary>
''' 替换表达式式中的十六进制占位符为实际内容,例如替换B4为buf中的第4位即buf(4)的值
''' </summary>
''' <param name="buf"></param>
''' <param name="expressionString"></param>
''' <returns></returns>
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
''' <summary>
''' 获取表达式转换后的结果是否为真,0、false、空字符为假1true为真, 其余为通过计算不为0判断真假
''' </summary>
''' <param name="exp"></param>
''' <returns></returns>
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
''' <summary>
''' 获取double类型运算式字符串后缀表达式
''' </summary>
''' <param name="str">字符串表达式</param>
''' <returns></returns>
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
''' <summary>
''' 获取小数类型运算结果
''' </summary>
''' <param name="num1">浮点型数1</param>
''' <param name="num2">浮点型数2</param>
''' <param name="c">运算符</param>
''' <returns></returns>
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
''' <summary>
''' 获取符号的优先级
''' </summary>
''' <param name="c">运算符号</param>
''' <returns></returns>
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
''' <summary>
''' 校验字符合法性0为数字1为运算符-1为未使用的运算符
''' </summary>
''' <param name="c">需要校验的字符</param>
''' <returns></returns>
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
''' <summary>
''' 校验运算式字符串合法性(todo:待进一步完善检测逻辑)
''' </summary>
''' <param name="str">需要校验的字符串</param>
''' <returns></returns>
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
'''' <summary>
'''' 获取int类型运算式字符串后缀表达式
'''' </summary>
'''' <param name="str">字符串表达式</param>
'''' <returns></returns>
'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
'''' <summary>
'''' 获取整形的运算结果
'''' </summary>
'''' <param name="num1">整数1</param>
'''' <param name="num2">整数2</param>
'''' <param name="c">运算符</param>
'''' <returns>预算结果</returns>
'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
''' <summary>
''' 返回表达式的值 'Momo 2022-11-10 增加 、Momo 2023-12-15 错误时抛出错误而不是弹窗
''' </summary>
''' <returns></returns>
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