средство проверки синтаксиса математики, написанное на python - PullRequest
9 голосов
/ 03 февраля 2011

Все, что мне нужно, это проверить, используя python, является ли строка допустимым математическим выражением или нет.

Для простоты, скажем, мне просто нужны + - * / операторы (+ - как унарные тоже) счисла и вложенные скобки.Я добавляю также простые имена переменных для полноты.

Так что я могу проверить это следующим образом:

test("-3 * (2 + 1)") #valid
test("-3 * ")        #NOT valid

test("v1 + v2")      #valid
test("v2 - 2v")      #NOT valid ("2v" not a valid variable name)

Я пытался pyparsing , но просто пробовал пример: "простой анализатор алгебраических выражений, который выполняет +,-,*,/ и ^ арифметические операции " Я получаю недопустимый код, а также пытаюсь его исправить. Я всегда получаю неверный синтаксис, анализируемый без вызова исключения.просто попробуйте :

>>>test('9', 9)
9 qwerty = 9.0 ['9'] => ['9']
>>>test('9 qwerty', 9)
9 qwerty = 9.0 ['9'] => ['9']

оба теста пройден ... o_O

Любой совет?

Ответы [ 5 ]

3 голосов
/ 03 февраля 2011

Это потому, что код синтаксического анализа разрешает функции. (И, между прочим, он делает намного больше, чем вам нужно, т.е. создайте стек и оцените это.)

Для начала, вы можете удалить pi и ident (и, возможно, что-то еще, что мне сейчас не хватает) из кода, чтобы запретить символы.

Причина в другом: парсеры PyParsingне будет пытаться использовать весь ввод по умолчанию.Вы должны добавить + StringEnd() (и импортировать его, конечно) в конец expr, чтобы он потерпел неудачу, если не может проанализировать весь ввод.В этом случае pyparsing.ParseException будет повышен.(Источник: http://pyparsing -public.wikispaces.com / FAQs )

Если вы хотите научиться немного разбираться, то, что вам нужно, может быть построено менее чем за тридцать строк слюбая приличная библиотека для разбора (мне нравится LEPL ).

1 голос
/ 04 февраля 2011

Добавление parseAll=True к вызову parseString преобразует этот анализатор в валидатор.

1 голос
/ 03 февраля 2011

Вы можете попробовать создать простой синтаксический анализатор самостоятельно, чтобы токенизировать строку арифметического выражения, а затем построить дерево выражений, если дерево допустимо (все листья являются операндами, а все внутренние узлы являются операторами), тогда вы можете сказать выражение допустимо.

Основная концепция - создать несколько вспомогательных функций для создания вашего парсера.

def extract() получит следующий символ из выражения
def peek() аналогично извлечению, но используется, если нет пробела для проверки следующего символа
get_expression()
get_next_token()

В качестве альтернативы, если вы можете гарантировать пробел между символами, вы можете использовать split() для выполнения всех токенизаций.

Затем вы строите свое дерево и оцениваете, правильно ли оно структурировано

Попробуйте это для получения дополнительной информации: http://effbot.org/zone/simple-top-down-parsing.htm

1 голос
/ 03 февраля 2011

Почему бы просто не оценить его и не уловить синтаксическую ошибку?

from math import *

def validateSyntax(expression):
  functions = {'__builtins__': None}
  variables = {'__builtins__': None}

  functions = {'acos': acos,
               'asin': asin,
               'atan': atan,
               'atan2': atan2,
               'ceil': ceil,
               'cos': cos,
               'cosh': cosh,
               'degrees': degrees,
               'exp': exp,
               'fabs':fabs,
               'floor': floor,
               'fmod': fmod,
               'frexp': frexp,
               'hypot': hypot,
               'ldexp': ldexp,
               'log': log,
               'log10': log10,
               'modf': modf,
               'pow': pow,
               'radians': radians,
               'sin': sin,
               'sinh': sinh,
               'sqrt': sqrt,
               'tan': tan,
               'tanh': tanh}

  variables = {'e': e, 'pi': pi}

  try:
    eval(expression, variables, functions)
  except (SyntaxError, NameError, ZeroDivisionError):
    return False
  else:
    return True

Вот несколько примеров:

> print validSyntax('a+b-1') # a, b are undefined, so a NameError arises.
> False

> print validSyntax('1 + 2')
> True

> print validSyntax('1 - 2')
> True

> print validSyntax('1 / 2')
> True

> print validSyntax('1 * 2')
> True

> print validSyntax('1 +/ 2')
> False

> print validSyntax('1 + (2')
> False

> print validSyntax('import os')
> False

> print validSyntax('print "asd"')
> False

> print validSyntax('import os; os.delete("~\test.txt")')
> False # And the file was not removed

Он ограничен только математическими операциями, поэтому должен работать немного лучше, чем грубый eval.

0 голосов
/ 04 февраля 2011

Если вы заинтересованы в изменении пользовательского механизма математической оценки, написанного на Python, чтобы он вместо этого был валидатором, вы можете начать с Evaluator 2.0 (Python 3.x) и Math_Evaluator (Python 2.x). Они не являются готовыми решениями, но позволят вам полностью настроить все, что вы пытаетесь сделать, в точности, используя (надеюсь) простой для чтения код Python. Обратите внимание, что "и" & "или" рассматриваются как операторы.

...