![]() |
| ||
| Visal has contributed code for computing a formula. I have updated his code to reflect vb.net coding style. I have also refactored the code, so it is easier to understand. I have not checked the code. The vb.net project files are as attached. Jerry Dusing (email: jerrydusing@yahoo.com) |
''' <summary> ''' To use this class do the following assignment ''' Value = StringCalculator.Calculate("Formula String") ''' </summary> ''' <remarks></remarks> Public Class StringCalculator ' Updated to VB.net 2005 by Jerry W. A. Dusing ' Email : jerrydusing@yahoo.com ' Refactored from code initially created by Visal ' Email : invisal@gmail.com' ' Vote for Visal in PSCODE through the link: ' http://www.pscode.com/vb/scripts/showcode.asp?txtCodeId=59600&lngWId=1 #Region "Public methods" ''' <summary> ''' Computes the value of a given formula. ''' ''' </summary> ''' <param name="pFormula">string formula</param> ''' <returns>Double</returns> ''' <remarks> ''' Supports the functions: cos, sin, log, abs, and mod. ''' For example : [10*2+(2+3)]/(5 mod 4) ''' </remarks> Public Shared Function Calculate(ByVal pFormula As String) As Double Try If FoundParenthesis(pFormula) Then Return Calculate(ExpressionInParenthesis(pFormula)) ElseIf InStr(1, pFormula, "abs", vbTextCompare) > 0 Then Return Absolute(pFormula) ElseIf InStr(1, pFormula, "cos", vbTextCompare) > 0 Then Return Cosine(pFormula) ElseIf InStr(1, pFormula, "sin", vbTextCompare) > 0 Then Return Sine(pFormula) ElseIf InStr(1, pFormula, "log", vbTextCompare) > 0 Then Return Logarithm(pFormula) ElseIf InStr(1, pFormula, "mod") > 1 Then Return Modulo(pFormula) ElseIf InStr(1, pFormula, "+") > 1 Then Return Plus(pFormula) ElseIf InStr(1, pFormula, "-") > 1 Then Return Minus(pFormula) ElseIf InStr(1, pFormula, "*") > 1 Then Return Multiply(pFormula) ElseIf InStr(1, pFormula, "/") > 1 Then Return Divide(pFormula) ElseIf InStr(1, pFormula, "^") > 1 Then Return Exponential(pFormula) Else If IsNumeric(pFormula) = True Then Return CDbl(pFormula) Else Throw New Exception("Unrecognized formula expresion.") End If End If Catch ex As Exception Throw New Exception(ex.Message) End Try End Function #End Region #Region "Private methods" Private Shared Function Absolute( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "abs", vbTextCompare) Dim exp As String = "" For i As Integer = index + 3 To Len(pExp) Dim cmid As String = Mid(pExp, i, 1) If IsNumeric(cmid) = True Or cmid = "." Or cmid = "," Then exp = exp & cmid Else Exit For End If Next If exp <> "" Then ' replace the adsolute number with the answer exp = Replace(pExp, "abs" & exp, Math.Abs(CDbl(exp)).ToString()) Return Calculate(exp) Else Mid(pExp, index, 3) = "000" Return Calculate(pExp) End If End Function Private Shared Function Cosine( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "cos", vbTextCompare) ' clear all the text in exp2 Dim exp As String = "" ' get cosines angle For i As Integer = index + 3 To Len(pExp) Dim cmid As String = Mid(pExp, i, 1) If IsNumeric(cmid) = True Or cmid = "." Or cmid = "," Then exp = exp & cmid Else Exit For End If Next If exp <> "" Then ' replace cosines with the answer exp = Replace(pExp, "cos" & exp, Math.Cos(CDbl(exp)).ToString()) Return Calculate(exp) Else Mid(pExp, index, 3) = "000" Return Calculate(pExp) End If End Function Private Shared Function Divide( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "/") Dim divisor As Double = Calculate(Right(pExp, Len(pExp) - index)) If divisor = 0.0! Then Throw New Exception("Division by zero!") Else Return Calculate(Left(pExp, index - 1)) / divisor End If End Function Private Shared Function Exponential( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "^") Return Calculate(Left(pExp, index - 1)) ^ Calculate(Right(pExp, Len(pExp) - index)) End Function Private Shared Function ExpressionInParenthesis( _ ByVal pExp As String _ ) As String Dim sIndex, eIndex As Integer 'searching for ")" MatchClosingParenthesis(pExp, sIndex, eIndex) If eIndex <= sIndex + 1 Then ' check if () is empty or not Return Replace(pExp, "()", "0") Else ' get expression between "(" and ")" Dim RetVal As String = Mid(pExp, sIndex + 1, eIndex - (sIndex + 1)) Return Replace(pExp, "(" & RetVal & ")", Calculate(RetVal).ToString()) End If End Function Private Shared Function FoundParenthesis( _ ByRef pExp As String _ ) As Boolean pExp = Replace(pExp, "\", "/") ' \ and / are same division pExp = Replace(pExp, "[", "(") ' "[" and "(" are the same also "]" and ")" pExp = Replace(pExp, "]", ")") Return InStr(1, pExp, "(") > 0 End Function Private Shared Function Logarithm( _ ByVal pExp As String) As Double Dim index As Integer = InStr(1, pExp, "log", vbTextCompare) ' clear all the text in exp2 Dim exp As String = "" ' get number For i As Integer = index + 3 To Len(pExp) Dim cmid As String = Mid(pExp, i, 1) If IsNumeric(cmid) = True Or cmid = "." Or cmid = "," Then exp = exp & cmid Else Exit For End If Next i If exp <> "" Then ' replace logarithmic with the answer exp = Replace(pExp, "log" & exp, Math.Log(CDbl(exp)).ToString()) Return Calculate(exp) Else Mid(pExp, index, 3) = "000" Return Calculate(pExp) End If End Function Private Shared Sub MatchClosingParenthesis( _ ByRef pExp As String, _ ByRef pStart As Integer, _ ByRef pEnd As Integer _ ) Dim count As Integer For pEnd = (pStart + 1) To Len(pExp) Select Case Mid(pExp, pEnd, 1) Case "(" count += 1 Case ")" If count = 0 Then Exit For count -= 1 End Select Next pEnd If count > 0 Then ' if no ")" create ")" automatically pExp = pExp & Replace(Space(count + 1), " ", ")") pEnd = pEnd + count End If End Sub Private Shared Function Minus( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "-") Return Calculate(Left(pExp, index - 1)) - Calculate(Right(pExp, Len(pExp) - index)) End Function Private Shared Function Modulo( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "mod") Return Calculate(Left(pExp, index - 1)) Mod Calculate(Right(pExp, Len(pExp) - (index + 2))) End Function Private Shared Function Multiply( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "*") Return Calculate(Left(pExp, index - 1)) * Calculate(Right(pExp, Len(pExp) - index)) End Function Private Shared Function Plus( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "+") Return Calculate(Left(pExp, index - 1)) + Calculate(Right(pExp, Len(pExp) - index)) End Function Private Shared Function Sine( _ ByVal pExp As String _ ) As Double Dim index As Integer = InStr(1, pExp, "sin", vbTextCompare) ' clear all the text in exp2 Dim exp As String = "" ' get sines angle For i As Integer = index + 3 To Len(pExp) Dim cmid As String = Mid(pExp, i, 1) If IsNumeric(cmid) = True Or cmid = "." Or cmid = "," Then exp = exp & cmid Else Exit For End If Next i If exp <> "" Then ' replace Sines with the answer exp = Replace(pExp, "sin" & exp, Math.Sin(CDbl(exp)).ToString()) Return Calculate(exp) Else Mid(pExp, index, 3) = "000" Return Calculate(pExp) End If End Function #End Region End Class