Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - Общий форум

Страница: 1 |

 

  Вопрос: Помогите разобраться со строками. Добавлено: 02.02.08 18:40  

Автор вопроса:  Diman | Web-сайт: Не имею | ICQ:
Пишу калькулятор.Мне нужно перевести строку в числовой формат, строка примерного вида "2*3^(2+1)-3".Суть заключается в том, чтоб она перевелась в число выполнив все действия:*,^,+,-и т.д. Т.е."2*3^(2+1)-3"=2*3^(2+1)-3=51.

Ответить

  Ответы Всего ответов: 5  

Номер ответа: 1
Автор ответа:
 ZagZag



ICQ: 295002202 

Вопросов: 87
Ответов: 1684
 Профиль | | #1 Добавлено: 02.02.08 18:57
Ну для начала проверяй синтаксис:
- Скобки чтоб все парные были
- Знакосочетаний типа 2*_+1 набыло, т.е. несколько знаков подряд не шли.

А потом... лучше примеры поищи. Были. Я точно видел.

Ответить

Номер ответа: 2
Автор ответа:
 Diman



ICQ:

Вопросов: 1
Ответов: 7
 Web-сайт: Не имею
 Профиль | | #2
Добавлено: 02.02.08 19:00

Не я имеют ввиду другое. Хотя бы знаешь операторы, при помощи которых можно перевести эту строку в число

Ответить

Номер ответа: 3
Автор ответа:
 ZagZag



ICQ: 295002202 

Вопросов: 87
Ответов: 1684
 Профиль | | #3 Добавлено: 02.02.08 19:15
Нет такого. Надо свой парсер писать или искать уже написанный.
А может и есть...

Ответить

Номер ответа: 4
Автор ответа:
 ZagZag



ICQ: 295002202 

Вопросов: 87
Ответов: 1684
 Профиль | | #4 Добавлено: 02.02.08 20:30
Во! Нашел вроде бы.
VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  ;DataBindingBehavior = 0  'vbNone
  ;DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "Expression"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private Const MyName As String = "ExpressionClass"

'Класс для вычисления выражений в строковой форме
'(c) Гергерт Сергей, 2003

'Магадан, 04.07.2003 01:10
'Всё, иду спать...

Private Const Plus As String = "+"
Private Const Minus As String = "-"

Private Const Mult As String = "*"
Private Const Div As String = "/"
Private Const DivInt As String = "\"

Private Const Power As String = "^"

Private Const LeftPar As String = ";("
Private Const RightPar As String = ";)"

Public Enum ExprErrors
  exprNoError
  exprErrorParentheses
  exprErrorInvalidExpression
  exprErrorUnknownFunction
End Enum

Public Function Value(ByVal E As String) As Double
Attribute Value.VB_UserMemId = 0
  Dim i As Long
  Dim tmpLng As Long, tmpStr As String
  
  E = LCase$(Replace(E, " ", vbNullString))
  E = Replace(E, RightPar + LeftPar, RightPar + Mult + LeftPar)
  
  'Сначал убедимся, что скобки расставлены верно.
  'Идём слева направо. Открывающая скобка - плюс 1,
  'закрывающая - минус 1. Всё время должно быть >=0, а в конце =0
  
  For i = 1 To Len(E)
    tmpStr = Mid$(E, i, 1)
    If tmpStr = LeftPar Then
      tmpLng = tmpLng + 1
    ElseIf tmpStr = RightPar Then
      tmpLng = tmpLng - 1
    End If
    If tmpLng < 0 Then Err.Raise exprErrorParentheses, MyName, "Parentheses do not match"
  Next
  If tmpLng Then Err.Raise exprErrorParentheses, MyName, "Parentheses do not match"
  
  Value = CalcSummand(E)
End Function

Private Function CalcSummand(S As String) As Double
  Dim i As Long, minPrior As Byte, minPriorPos As Long
  Dim NestingLevel As Long, tmpStr As String
  
  'Не пустая ли строка?
  If Len(S) = 0 Then Exit Function 'выходим с нулём
  
  'Проверяем, не являются ли самые внешние скобки лишними
  Do While LISP(S)
  Loop
  
  'Ищем первый оператор с минимальным приоритетом на текущем уровне вложенности
  minPrior = 2
  For i = 1 To Len(S)
    Select Case Mid$(S, i, 1)
    Case LeftPar
      NestingLevel = NestingLevel + 1
    Case RightPar
      NestingLevel = NestingLevel - 1
    Case Plus, Minus
      If NestingLevel = 0 Then
        minPrior = 0
        minPriorPos = i
        Exit For
      End If
    Case Mult, Div, DivInt
      If NestingLevel = 0 Then
        If minPrior = 2 Then
          minPrior = 1
          minPriorPos = i
        Else
          If minPriorPos = 0 Then minPriorPos = i
        End If
      End If
    Case Power
      If NestingLevel = 0 Then
        If minPrior = 2 And minPriorPos = 0 Then minPriorPos = i
      End If
    End Select
  Next
  
  If minPriorPos = 0 Then
    'Сие означает, что операторов на текущем уровне вложенности нет.
    'Это, в свою очередь, означает, что либо операнд есть число,
    'либо он есть функция.
    CalcSummand = IsFunction(S)
    If CalcSummand >= 0 Then
      Exit Function 'операнд был числом, и он вычислен
    Else
      'Операнд был функцией. Других вариантов нет, т.к. ошибка генерится в IsFunction
      'Переменная minPriorPos нам больше не нужна по прямому назначению.
      'Поэтому заюзаем её для других целей. Просто очень капризная рекурсия
      'в VB, стэк экономим-с...
      minPriorPos = InStr(S, LeftPar)
      tmpStr = Left$(S, minPriorPos - 1)
      'Вот почему нельзя вызывать CallByName от модуля?
      'Сколько бы гемора исчезло...
      Select Case tmpStr
      Case "abs"
        CalcSummand = Abs(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case "atn"
        CalcSummand = Atn(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case "cos"
        CalcSummand = Cos(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case "exp"
        CalcSummand = Exp(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case "log"
        CalcSummand = Log(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case "sgn"
        CalcSummand = Sgn(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case "sin"
        CalcSummand = Sin(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case "sqr"
        CalcSummand = Sqr(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case "tan"
        CalcSummand = Tan(CalcSummand(Mid$(S, minPriorPos + 1, Len(S) - minPriorPos - 1)))
      Case Else
        Err.Raise exprErrorUnknownFunction, MyName, "Unknown function " + UCase$(tmpStr) + " detected"
      End Select
    End If
  Else
    'Нашли искомый оператор. Рекурсия...
    If minPriorPos = 1 Then 'выражение типа -expr
      tmpStr = Left$(S, 1)
      If tmpStr = Plus Or tmpStr = Minus Then
        CalcSummand = IIf(tmpStr = Minus, -1, 1) * CalcSummand(Mid$(S, 2))
      Else
        Err.Raise exprErrorInvalidExpression, MyName, "Expression is invalid"
      End If
    Else                    'обычное a +-*/\^ b
      Select Case Mid$(S, minPriorPos, 1)
      Case Plus
        CalcSummand = CalcSummand(Left$(S, minPriorPos - 1)) + CalcSummand(Right$(S, Len(S) - minPriorPos))
      Case Minus
        CalcSummand = CalcSummand(Left$(S, minPriorPos - 1)) - CalcSummand(Right$(S, Len(S) - minPriorPos))
      Case Mult
        CalcSummand = CalcSummand(Left$(S, minPriorPos - 1)) * CalcSummand(Right$(S, Len(S) - minPriorPos))
      Case Div
        'Ошибку деления на ноль VB сгенерит и без нас...
        CalcSummand = CalcSummand(Left$(S, minPriorPos - 1)) / CalcSummand(Right$(S, Len(S) - minPriorPos))
      Case DivInt
        CalcSummand = CalcSummand(Left$(S, minPriorPos - 1)) \ CalcSummand(Right$(S, Len(S) - minPriorPos))
      Case Power
        CalcSummand = CalcSummand(Left$(S, minPriorPos - 1)) ^ CalcSummand(Right$(S, Len(S) - minPriorPos))
      Case Else
        'В принципе, этого возникать не должно никогда...
        Err.Raise exprErrorInvalidExpression, MyName, "Expression is invalid"
      End Select
    End If
  End If
End Function

Private Function LISP(ByRef S As String) As Boolean
  Dim i As Long, tmp As Long
  
  'LISP = Lots of Idiot Silly Parentheses!
  'Фанаты языка LISP в шоке и готовят помидоры... :)
  
  'Если уровень скобок по ходу выражения опустится до нуля,
  'и это будет не конец выражения, то начальные и конечные
  'скобки нужны, поскольку принадлежат разным группам.
  'Иначе их можно удалить.
  
  If Left$(S, 1) = LeftPar And Right$(S, 1) = RightPar Then
    For i = 1 To Len(S)
      If Mid$(S, i, 1) = LeftPar Then
        tmp = tmp + 1
      ElseIf Mid$(S, i, 1) = RightPar Then
        tmp = tmp - 1
        If tmp = 0 And i <> Len(S) Then Exit Function
      End If
    Next
  Else
    Exit Function
  End If
  
  'Скобки нужно удалить
  S = Mid$(S, 2, Len(S) - 2)
  LISP = True
End Function

Private Function IsFunction(F As String) As Double
  'Функция - несколько подряд идущих букв и выражение в скобках.
  'И больше ничего! Выражение типа "функция + функция" сюда попадать не должно,
  'по логике основной части программы
  Dim i As Long
  
  'правильность скобок гарантируется вызывающим кодом, поэтому достаточно
  'проверить наличие одной, а не обоих
  i = InStr(F, LeftPar)
  If i = 0 Then
    'Явно не функция. Может, число?
    For i = 1 To Len(F)
      If InStr("0123456789.", Mid$(F, i, 1)) = 0 Then Exit For
    Next
    If i = Len(F) + 1 Then IsFunction = Val(F) Else Err.Raise exprErrorInvalidExpression, MyName, "Expression is invalid"
    'логика программы такова, что отрицательное число вычисляется
    'как (-)(expression), поэтому здесь всегда результат положительный,
    'и можно использовать отрицательные числа как флаги
    Exit Function
  End If
  
  'левая (а значит, и правая) скобки есть, и это не начальные ненужные скобки.
  'Слева от левой скобки должнно быть имя функции. Его правильность будет
  'анализировать вызывающий код
  IsFunction = -1 'Флаг, что функция
End Function

Ответить

Номер ответа: 5
Автор ответа:
 Diman



ICQ:

Вопросов: 1
Ответов: 7
 Web-сайт: Не имею
 Профиль | | #5
Добавлено: 02.02.08 20:47
Спасибо

Ответить

Страница: 1 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам