Безопасный парсер выражений в Python - PullRequest
14 голосов
/ 27 августа 2010

Как я могу позволить пользователям безопасно выполнять математические выражения?Нужно ли писать полный анализатор?

Есть ли что-то вроде ast.literal_eval () , но для выражений?

Ответы [ 5 ]

10 голосов
/ 27 августа 2010

На странице примеров Pyparsing перечислены несколько синтаксических анализаторов выражений:

http://pyparsing.wikispaces.com/file/view/fourFn.py - Традиционная реализация синтаксического анализатора / оценщика инфиксного обозначения с использованием pyparsing (несмотря на его название, на самом деле это 5-функциональная арифметика плюс несколько функций trig)

http://pyparsing.wikispaces.com/file/view/simpleBool.py - Булев синтаксический анализатор / анализатор инфиксных обозначений, использующий вспомогательный метод pyparsing operatorPrecedence, который упрощает определение обозначений инфиксных операторов

http://pyparsing.wikispaces.com/file/view/simpleArith.py http://pyparsing.wikispaces.com/file/view/eval_arith.py - Пара примеров, восстанавливающих fourFn.py с использованием operatorPrecedence. Первый просто анализирует и возвращает дерево разбора, второй добавляет логику оценки.

3 голосов
/ 27 августа 2010

Какие выражения вы хотите? Переменная присваивания? Оценка функции?

SymPy стремится стать полноценным Python CAS.

1 голос
/ 27 августа 2010

Несколько недель назад я делал подобные вещи, но для логических выражений (или, а не для сравнения, скобок и т. Д.). Я сделал это с помощью Ply парсера. Я создал простой лексер и парсер. Синтаксический анализатор создал дерево AST, которое позже использовалось для выполнения вычислений. Делая это таким образом, вы можете полностью контролировать, что вводит пользователь, потому что будут проанализированы только выражения, совместимые с грамматикой.

0 голосов
/ 27 августа 2010

математические функции будут состоять из цифровых символов и знаков пунктуации, возможно, «E» или «e», если вы разрешите научную запись для рациональных чисел, и единственное (другое) законное использование буквенных символов будет, если вы разрешите / предоставите определенные математические вычисленияфункции (например, stddev).Таким образом, должно быть тривиально бегать по строке для буквенных символов и проверять, что следующий бит не является подозрительным, а затем просто оценивать строку в блоке try / Кроме.

Перечитайте комментарии, полученные в этом ответе... Я согласен, что этот подход играет с огнем.Тем не менее, это не значит, что это не может быть сделано безопасно.Я новичок в Python (<2 месяца), так что, возможно, не знаю обходных путей, к которым это уязвимо (и, конечно, новая версия Python всегда может сделать код небезопасным в будущем), но - насколько это мало (главным образом, мое собственное развлечение) - вот мой недостаток: </p>

def evalMaths(s):
    i = 0
    while i < len(s):
        while s[i].isalpha() and i < len(s):
            idn += s[i]
            i += 1
        if (idn and idn != 'e' and idn != 'abs' and idn != 'round'):
            raise Exception("you naughty boy: don't " + repr(idn))
        else:
            i += 1
    return eval(s)

Мне было бы очень интересно услышать, если / как это можно обойти ... (^_^) Кстати, я знаю, что вы можете позвонитьфункции, такие как abs2783 или _983 - если они существуют, но они не будут.Я имею в виду что-то практическое.

На самом деле, если кто-то сможет это сделать, я создам вопрос с 200 щедротами и приму их ответ.

0 голосов
/ 27 августа 2010

Да.Даже если бы для выражений был эквивалент ast.literal_eval(), выражение Python может быть чем-то большим, чем просто математическое выражение, например, произвольный вызов функции.

Меня не удивит, еслиуже есть хороший синтаксический анализатор / оценщик математических выражений, доступный в каком-то модуле с открытым исходным кодом, но если нет, то написать свой собственный довольно легко.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...