''' <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