第一次提交至Git
This commit is contained in:
539
UTS_Core/Expression/StringExpression.vb
Normal file
539
UTS_Core/Expression/StringExpression.vb
Normal file
@@ -0,0 +1,539 @@
|
||||
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、空字符为假,1,true为真, 其余为通过计算不为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
|
||||
Reference in New Issue
Block a user