''' ''' Used to convert strings into various types. ''' Public Class ScriptConversion Enum Associativity Right Left End Enum ''' ''' Converts an expression into a . ''' Public Shared Function ToDouble(ByVal expression As Object) As Double Dim input As String = expression.ToString() Dim retError As Boolean = False Dim retDbl As Double = 0D retDbl = InternalToDouble(input, retError) If retError = False Then Return retDbl Else If IsArithmeticExpression(expression) = True Then Dim postFix As String = ToPostfix(expression.ToString()) Return EvaluatePostfix(postFix) Else Return 0D End If End If End Function ''' ''' If the input can be evaluated into a number. ''' Public Shared Function IsArithmeticExpression(ByVal expression As Object) As Boolean Dim retError As Boolean = False Dim postfix As String = ToPostfix(expression.ToString(), retError) If retError = False Then EvaluatePostfix(postfix, retError) Return retError = False Else Return False End If End Function ''' ''' Evaluates a math expression in the postfix notation. Example: "2 3 +". ''' ''' The postfix string. Private Shared Function EvaluatePostfix(ByVal input As String, Optional ByRef hasError As Boolean = False) As Double Dim stack As New List(Of Double) Dim tokens As List(Of Char) = input.ToCharArray().ToList() Dim cNumber As String = "" While tokens.Count > 0 Dim token As Char = tokens(0) tokens.RemoveAt(0) If IsNumber(token) = True Then cNumber &= token.ToString() ElseIf cNumber.Length > 0 Then stack.Insert(0, InternalToDouble(cNumber)) cNumber = "" End If If cNumber.Length > 0 And tokens.Count = 0 Then stack.Insert(0, InternalToDouble(cNumber)) cNumber = "" End If If IsOperator(token) = True Then If stack.Count >= 2 Then Dim v2 As Double = stack(0) Dim v1 As Double = stack(1) stack.RemoveAt(0) stack.RemoveAt(0) Dim result As Double = 0 Select Case token.ToString() Case "+" result = v1 + v2 Case "-" result = v1 - v2 Case "*" result = v1 * v2 Case "/" If v2 = 0 Then Logger.Log(Logger.LogTypes.Warning, "Script.vb: Cannot evaluate """ & input.ToString() & """ as an arithmetic expression.") hasError = True Return 0 Else result = v1 / v2 End If Case "^" result = v1 ^ v2 Case "%" result = v1 Mod v2 End Select stack.Insert(0, result) Else Logger.Log(Logger.LogTypes.Warning, "Script.vb: Cannot evaluate """ & input.ToString() & """ as an arithmetic expression.") hasError = True Return 0 End If End If End While If stack.Count = 1 Then Return stack(0) Else Logger.Log(Logger.LogTypes.Warning, "Script.vb: Cannot evaluate """ & input.ToString() & """ as an arithmetic expression.") hasError = True Return 0 End If End Function ''' ''' Converts an infix notation to postfix notation. ''' ''' The infix notation. Example: "2+3". Private Shared Function ToPostfix(ByVal input As String, Optional ByRef hasError As Boolean = False) As String If input.Trim().StartsWith("-") Then input = "0" & input End If Dim tokens As List(Of Char) = input.ToCharArray().ToList() Dim stack As New List(Of Char) Dim output As String = "" Dim cNumber As String = "" While tokens.Count > 0 Dim token As Char = tokens(0) tokens.RemoveAt(0) ' Token is a number: If IsNumber(token) = True Then cNumber &= token.ToString() ElseIf cNumber.Length > 0 Then output &= cNumber.ToString() & " " ' Add to the output. cNumber = "" End If If cNumber.Length > 0 And tokens.Count = 0 Then output &= cNumber.ToString() & " " cNumber = "" End If ' Token is an operator: If IsOperator(token) = True Then Dim o1 As Char = token While stack.Count > 0 AndAlso IsOperator(stack(0)) = True AndAlso ((GetAssociativity(o1) = Associativity.Left And GetPrecedence(o1) <= GetPrecedence(stack(0))) Or (GetAssociativity(o1) = Associativity.Right And GetPrecedence(o1) < GetPrecedence(stack(0)))) output &= stack(0).ToString() & " " stack.RemoveAt(0) End While stack.Insert(0, o1) End If ' Token is a left parenthesis: If token = "("c Then stack.Insert(0, token) End If ' Token is a right parenthesis: If token = ")"c Then If stack.Count > 0 Then While stack.Count > 0 If stack(0) = "("c Then stack.RemoveAt(0) Exit While Else output &= stack(0).ToString() & " " stack.RemoveAt(0) End If End While Else Logger.Log(Logger.LogTypes.Warning, "Script.vb: Cannot convert """ & input.ToString() & """ to an arithmetic expression.") hasError = True Return "0" End If End If End While While stack.Count > 0 If stack(0) = "("c Or stack(0) = ")"c Then Logger.Log(Logger.LogTypes.Warning, "Script.vb: Cannot convert """ & input.ToString() & """ to an arithmetic expression.") hasError = True Return "0" Else output &= stack(0).ToString() & " " stack.RemoveAt(0) End If End While Return output End Function ''' ''' If the token is a number or part of one. ''' ''' The token. Private Shared Function IsNumber(ByVal token As Char) As Boolean Return "0123456789.,".ToCharArray().Contains(token) End Function ''' ''' If the token is an operator. ''' ''' The token. Private Shared Function IsOperator(ByVal token As Char) As Boolean Return "+-*/^%".ToCharArray().Contains(token) End Function ''' ''' Returns the precedence for an operator. ''' ''' The operator. Private Shared Function GetPrecedence(ByVal [Operator] As Char) As Integer Select Case [Operator] Case "+"c, "-"c Return 2 Case "*"c, "/"c, "%"c Return 3 Case "^"c Return 4 End Select Return -1 End Function ''' ''' Returns if an operator has a Left or Right Associativity. ''' ''' The operator Private Shared Function GetAssociativity(ByVal [Operator] As Char) As Associativity Select Case [Operator] Case "^"c Return Associativity.Right Case Else Return Associativity.Left End Select End Function ''' ''' Tries to convert a single number into a . ''' Private Shared Function InternalToDouble(ByVal expression As String, Optional ByRef hasError As Boolean = False) As Double expression = expression.Replace(".", My.Application.Culture.NumberFormat.NumberDecimalSeparator) If StringHelper.IsNumeric(expression) Then Return System.Convert.ToDouble(expression) Else If expression.ToLower() = "false" Then Return 0 ElseIf expression.ToLower() = "true" Then Return 1 Else hasError = True Return 0 End If End If End Function ''' ''' Converts an expression into an . ''' ''' The expression to convert. Public Shared Function ToInteger(ByVal expression As Object) As Integer Return CInt(Math.Round(ToDouble(expression))) End Function ''' ''' Converts an expression to a . ''' ''' The expression to convert. Public Shared Function ToSingle(ByVal expression As Object) As Single Return CSng(ToDouble(expression)) End Function ''' ''' Converts an expression into a . ''' ''' The expression to convert. Public Shared Function ToBoolean(ByVal expression As Object) As Boolean Select Case expression.ToString().ToLower() Case "true", "1" Return True Case Else Return False End Select End Function ''' ''' Performs a check if an expression is a valid . ''' ''' The expression to perform the check on. Public Shared Function IsBoolean(ByVal expression As Object) As Boolean Dim s As String = expression.ToString() Dim validBools() As String = {"0", "1", "true", "false"} Return validBools.Contains(s.ToLower()) End Function End Class