ArXen42

ArithmeticParser

Apr 24th, 2016
292
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 7.29 KB | None | 0 0
  1. Module Module1
  2.   ''' <summary>
  3.   ''' Вычисляет арифметическое выражение с помощью алгоритма Бауэра и Замельзона.
  4.   ''' </summary>
  5.   Public Function CalculateString(expression As String) As Double
  6.     Dim normalizedExpression As String = PreprocessString(expression)
  7.  
  8.     translatorStack = New CustomStack(Of String)()
  9.     interpreterStack = New CustomStack(Of Double)()
  10.     translatorStack.Push(EmptyOperation)
  11.  
  12.     For Each s As String In (normalizedExpression & Space(1) & EmptyOperation).Split(" "c)
  13.       Dim value As Double
  14.       If Double.TryParse(s, value) Then
  15.         interpreterStack.Push(value)
  16.       Else
  17.         Dim lastOperationInStack As String = translatorStack.Peek()
  18.         transitionTable(VerticalIndexesMap(lastOperationInStack), HorizontalIndexesMap(s))(s)
  19.       End If
  20.     Next
  21.  
  22.     Return interpreterStack.Peek()
  23.   End Function
  24.  
  25.   Private Const EmptyOperation As String = "$"
  26.   Private Const OpeningBracket As String = "("
  27.   Private Const Plus As String = "+"
  28.   Private Const Minus As String = "-"
  29.   Private Const Multiplication As String = "*"
  30.   Private Const Division As String = "/"
  31.   Private Const ClosingBracket As String = ")"
  32.  
  33.   'Словарь, связывающий строковое обозначение арифметических операций и функции, их вычисляющие.
  34.   Private arithmeticalFunctions As Dictionary(Of String, Func(Of Double, Double, Double)) = New Dictionary(Of String, Func(Of Double, Double, Double))() From {
  35.       {Plus, Function(a, b) a + b},
  36.       {Minus, Function(a, b) a - b},
  37.       {Multiplication, Function(a, b) a * b},
  38.       {Division, Function(a, b) a / b}
  39.   }
  40.  
  41.   Private translatorStack As CustomStack(Of String)
  42.   Private interpreterStack As CustomStack(Of Double)
  43.  
  44.   Private f1 As Action(Of String) = Sub(inputOperation As String)
  45.                                       translatorStack.Push(inputOperation)
  46.                                     End Sub
  47.  
  48.   Private f2 As Action(Of String) = Sub(inputOperation As String)
  49.                                       Dim lastOperationInStack As String = translatorStack.Pop()
  50.                                       Dim operand2 As Double = interpreterStack.Pop()
  51.                                       Dim operand1 As Double = interpreterStack.Pop()
  52.  
  53.                                       Dim result As Double = arithmeticalFunctions(lastOperationInStack)(operand1, operand2)
  54.                                       interpreterStack.Push(result)
  55.                                       translatorStack.Push(inputOperation)
  56.                                     End Sub
  57.  
  58.   Private f3 As Action(Of String) = Sub(inputOperation As String)
  59.                                       translatorStack.Pop()
  60.                                     End Sub
  61.  
  62.   Private f4 As Action(Of String) = Sub(inputOperation As String)
  63.                                       Dim lastOperationInStack As String = translatorStack.Pop()
  64.                                       Dim operand2 As Double = interpreterStack.Pop()
  65.                                       Dim operand1 As Double = interpreterStack.Pop()
  66.  
  67.                                       Dim result As Double = arithmeticalFunctions(lastOperationInStack)(operand1, operand2)
  68.                                       interpreterStack.Push(result)
  69.  
  70.                                       lastOperationInStack = translatorStack.Peek()
  71.                                       transitionTable(VerticalIndexesMap(lastOperationInStack), HorizontalIndexesMap(inputOperation))(inputOperation)
  72.                                     End Sub
  73.  
  74.   Private f5 As Action(Of String) = Sub(inputOperation As String)
  75.                                       Throw New InvalidBracketsPlacementException("Incorrect placement of the brackets.")
  76.                                     End Sub
  77.  
  78.   Private f6 As Action(Of String) = Sub(inputOperation As String)
  79.                                     End Sub
  80.  
  81.   Private ReadOnly HorizontalIndexesMap As Dictionary(Of String, Int32) = New Dictionary(Of String, Int32)() From {
  82.       {EmptyOperation, 0},
  83.       {OpeningBracket, 1},
  84.       {Plus, 2},
  85.       {Minus, 3},
  86.       {Multiplication, 4},
  87.       {Division, 5},
  88.       {ClosingBracket, 6}
  89.   }
  90.  
  91.   Private ReadOnly VerticalIndexesMap As Dictionary(Of String, Int32) = New Dictionary(Of String, Int32)() From {
  92.       {EmptyOperation, 0},
  93.       {OpeningBracket, 1},
  94.       {Plus, 2},
  95.       {Minus, 3},
  96.       {Multiplication, 4},
  97.       {Division, 5}
  98.   }
  99.  
  100.   Private ReadOnly transitionTable As Action(Of String)(,) = New Action(Of String)(,) {
  101.       {f6, f1, f1, f1, f1, f1, f5},
  102.       {f5, f1, f1, f1, f1, f1, f3},
  103.       {f4, f1, f2, f2, f1, f1, f4},
  104.       {f4, f1, f2, f2, f1, f1, f4},
  105.       {f4, f1, f4, f4, f2, f2, f4},
  106.       {f4, f1, f4, f4, f2, f2, f4}
  107.   }
  108.  
  109.   ''' <summary>
  110.   ''' Разделяет элементы выражения во входной строке пробелами.
  111.   ''' </summary>
  112.   Private Function PreprocessString(inputExpression As String) As String
  113.     Dim resultExpression As String = ""
  114.  
  115.     inputExpression = String.Concat(inputExpression.Split(" "c))
  116.     inputExpression = Multiplication + inputExpression
  117.     'Умножение в начале не попадет в итоговое выражение, использовано для предотвращения вылета за границы массива и корректной обработки унарных плюса/минуса в начале выражения.
  118.  
  119.     For i As Int32 = 1 To inputExpression.Length - 2
  120.       Dim previousChar As Char = inputExpression(i - 1)
  121.       Dim currentChar As Char = inputExpression(i)
  122.       Dim nextChar As Char = inputExpression(i + 1)
  123.  
  124.       resultExpression += currentChar
  125.  
  126.       If NeedAddingSpace(previousChar, currentChar, nextChar) Then
  127.         resultExpression += Space(1)
  128.       End If
  129.     Next
  130.  
  131.     resultExpression += inputExpression.Last
  132.  
  133.     Return resultExpression
  134.   End Function
  135.  
  136.   ''' <summary>
  137.   ''' Вспомогательная функция, проверяющая необходимость добавления пробела внутри тройки символов из входной строки.
  138.   ''' </summary>
  139.   Private Function NeedAddingSpace(previousChar As Char, currentChar As Char, nextChar As Char)
  140.     If Char.IsDigit(currentChar) Then
  141.       If Not Char.IsDigit(nextChar) Then Return True
  142.     Else
  143.       If currentChar = Minus Or currentChar = Plus Then
  144.         If Not arithmeticalFunctions.ContainsKey(previousChar) Then Return True
  145.       Else
  146.         Return True
  147.       End If
  148.     End If
  149.  
  150.     Return False
  151.   End Function
  152.  
  153.   Sub Main()
  154.     Console.WriteLine("Enter arithmetic expression (space insensitive):")
  155.     Try
  156.       Console.WriteLine("Result: {0}",
  157.         CalculateString(Console.ReadLine())
  158.       )
  159.     Catch invalidBracketsEx As InvalidBracketsPlacementException
  160.       Console.WriteLine(invalidBracketsEx.Message)
  161.     Catch ex As Exception
  162.       Console.WriteLine("Error, invalid string.")
  163.     End Try
  164.   End Sub
  165. End Module
  166.  
  167. Public Class InvalidBracketsPlacementException
  168.   Inherits Exception
  169.   Public Sub New()
  170.     MyBase.New()
  171.   End Sub
  172.   Public Sub New(message As String)
  173.     MyBase.New(message)
  174.   End Sub
  175. End Class
Add Comment
Please, Sign In to add comment