Безопасный парсер выражений в Python
Как я могу позволить пользователям безопасно выполнять математические выражения? Нужно ли писать полный парсер? Есть ли что-то вроде ast.literal_eval(), но для выражений?
5 ответов
В странице примеров Pyparsing перечислены несколько парсеров выражений: http://pyparsing.wikispaces.com/file/view/fourFn.py — обычная реализация синтаксического анализа/оценки оценщика арифметических инфикс с использованием pyparsing (несмотря на свое имя, на самом деле это 5-функциональная арифметика, плюс несколько функций триггера) 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 . Первый просто анализирует и возвращает дерево синтаксического анализа, второе добавляет логику оценки.
Какие выражения вы хотите? Переменное назначение? Оценка функции?
SymPy стремится стать полноценным CAS Python.
Я могу изменить свои потребности в зависимости от имеющихся возможностей. SymPy выглядит интересно. Небольшая однофайловая библиотека была бы еще лучше.
@ Иво: возможности зависят от ваших потребностей! @Paul связал несколько простых способов сделать это с pyparsing . SymPy дает больше энергии при больших SymPy (большой, может быть медленным).
Несколько недель назад я сделал аналогичную вещь, но для логических выражений (или, а, нет, сравнений, круглых скобок и т.д.). Я сделал это, используя парсер Ply. Я создал простой лексер и парсер. Parser создал дерево AST, которое позже использовалось для выполнения вычислений. Выполняя это, вы сможете полностью контролировать, что вводит пользователь, потому что будут анализироваться только выражения, совместимые с грамматикой.
Да. Даже если для выражений был эквивалент выражения ast.literal_eval() , выражение Python может быть большим, чем просто чистое математическое выражение, например, произвольный вызов функции.
Меня не удивит, если в каком-то модуле с открытым исходным кодом есть хороший математический анализатор/оценщик математических выражений, но если нет, довольно легко написать один из своих.
Функции maths состоят из числовых символов и символов пунктуации, возможно «E» или «e», если вы допускаете научную нотацию для рациональных чисел, и единственным (другим) легальным использованием альфа-символов будет, если вы разрешаете/предоставляете конкретные математические данные функций (например, stddev). Итак, должно быть тривиально бегать по строке для альфа-символов и проверять следующий маленький бит не является подозрительным, а затем просто вычислять строку в блоке try/except.
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)
Мне было бы очень интересно узнать, как и как его можно обойти. (^_^) BTW/Я знаю, что вы можете вызывать функции, такие как abs2783 или _983, - если они существуют, но они не будут. Я имею в виду что-то практическое.
На самом деле, если кто-то может это сделать, я создам вопрос с 200 щедростью и приму их ответ.
-1 Не делай этого. eval -ный пользователя входной строки никогда не является хорошей идеей. Кто-то найдет способ обойти вашу защиту.
Как насчет обоснования, а не абсолютно бессмысленного утверждения? Это может быть не очень красиво, но если вы хотите что-то сделать, есть анализ затрат и выгод, когда у вас нет работающего решения, или возитесь с чем-то более сложным.
Я с Тони на этот раз. Инженерия - это понимание затрат и выгод. Правда, использование eval сопряжено с огромным риском, но есть ситуации, когда это уместно. У меня есть командная строка eval.py, которую я использую для быстрых вычислений. Я пользователь, так что использование eval прекрасно. Вы должны знать, что вы делаете, но «никогда» - это сильное слово.
@Ned: правда это. Я думал «ненадежный пользователь», и в этом случае я бы все равно сказал «никогда».
@Tony: если s не является строкой: pastebin.com/tennNUx2 . Если это так, вы можете вызвать ошибку с помощью 'round(round)' ; в противном случае я все еще думаю!
@Ned: хороший момент. Тем не менее, здесь явно задан вопрос о чем-то доказательстве злоупотреблений. @Alex: round (round) в порядке - я всегда говорил, чтобы это вызывалось в блоке try / кроме. Другие интересны: eval в строке '"()" * 8 ** 5' безопасен, и это то, что может использовать пользователь. Но eval с очень длинной строкой может дать сбой . если пользователь выполняет чтение без какого-либо ограничения на размер, то всегда есть уязвимость, хотя и не существующая, совершенно независимая от использования eval. Итак, согласитесь ли вы, что это отдельная проблема ввода / вывода, а не проблема?
Ещё вопросы
- 1 Объяснение о клоне необходим массив, содержащий клонируемые объекты
- 1 Алгоритм самой длинной палиндромной последовательности, анализ времени
- 0 JQuery Невозможно получить данные службы drupal через localhost: 8888
- 0 Почему этот код печатает 0
- 0 Независимые куки в разных папках
- 0 MySQL, как найти общие данные в нескольких таблицах
- 0 AngularJS -Контроллер не вызывается
- 1 Как получить первый элемент результата базы данных FIrebase в Python?
- 0 Как отобразить jquery querySelect или выбранный файл?
- 0 MySQL: mysqli_fetch_array ()
- 0 Поворот 3D камеры с помощью DirectX11
- 1 OAuth Google Plus войдите в систему: 400. Это ошибка. Ошибка: redirect_uri_mismatch
- 1 Knockout-привязка данных в функции
- 0 Вернуть n-ю строку
- 1 ngModel не может правильно определить изменения массива
- 0 Дизайн синхронизации потоков Qt
- 0 Как реализовать стек с помощью std :: vector?
- 0 Как сделать копии (новые экземпляры) функции замыкания?
- 0 Шаблон Joomla 3 - ширина модуля в обертке
- 0 PHP пока петли в то время как петли не работают
- 1 Элемент xmpmeta здесь не разрешен, когда я импортирую файл SVG
- 0 Создать сводную таблицу на основе двухколоночного SQL-запроса в PHP
- 0 Добавление пользовательских атрибутов в шаблон ejs
- 0 Не могу получить подготовленное заявление для печати в php
- 0 почему элемент указателя инициализирован ненулевым?
- 1 Удалить похожие элементы из списка
- 0 Принятие значений динамически создаваемых текстовых полей ввода HTML в C #
- 0 Как зациклить анимацию в jQuery
- 0 JQuery AutoCompleter - мульти и пользовательские данные
- 0 проверьте руководство, соответствующее вашей версии сервера MariaDB, на предмет правильного синтаксиса для использования рядом с 'WHERE \ r \ n
- 1 Как получить XML-контент в виде строки
- 1 Передача более одного значения из списка DropDown
- 0 Как прочитать значения динамической HTML-таблицы из текстового файла?
- 1 Я хочу нарисовать квадрат на картинке C #
- 0 Угловое изменение ввода текстового поля JS - Смотреть
- 0 Передача массива из JQuery в PHP через POST
- 0 Нужно ли закрывать соединение с пулом для каждого API в nodejs + mysql?
- 0 Угловой дизайн материала md-autocomplete с md-max-length и рисунком
- 1 Python re.findall возвращает только первый символ
- 1 Установка переменных среды в WinDbg
- 0 как получить необходимый контент, используя функцию strip_tags в php
- 0 Приведение / разыменование указателей на символы в двойной массив
- 1 перераспределить данные в гауссовом распределении с помощью pd.DataFrame
- 0 PHP строка для разделения массива
- 1 Числовое нечеткое сравнение Присоединение к Python / pandas dataframes
- 0 Hover FadeOut для определенного класса
- 1 ValueError: недопустимый литерал для int () с основанием 10: '' при запросе ввода
- 1 Есть ли способ получения информации, отображаемой в работающем приложении Android?
- 0 SQL Server против MySQL
- 1 Передать данные в pug с помощью pug-html-loader (не может прочитать свойство undefined)
Parsing A Boolean Expression in Python
Suppose we have a boolean expression, we have to find the result after evaluating that expression.
An expression can either be −
- "t", evaluating to True;
- "f", evaluating to False;
- "!(expression)", evaluating to the logical NOT of the inner expression;
- "&(expr1,expr2. )", evaluating to the logical AND of 2 or more inner expressions;
- "|(expr1,expr2. )", evaluating to the logical OR of 2 or more inner expressions;
So, if the input is like "|(!(t),&(t,f,t))", then the output will be fasle, this is because !(t) is false, then &(t,f,t) is also false, so the OR of all false values will be false.
To solve this, we will follow these steps −
- define solve(), this will take e, i
- if e[i] is same as "f", then −
- return (False, i + 1)
- if e[i] is same as ",", then −
- i := i + 1
- Ignore following part, skip to the next iteration
- return true when all elements are true in stack, otherwise false, i + 1
- return true when at least one elements is true in stack, otherwise false, i + 1
Let us see the following implementation to get better understanding −
Example
class Solution(object): def parseBoolExpr(self, expression): s,y = self.solve(expression,0) return s def solve(self,e,i): if e[i] =="f": return False,i+1 elif e[i] == "t": return True,i+1 op = e[i] i = i+2 stack = [] while e[i]!=")": if e[i] == ",": i+=1 continue res,i = self.solve(e,i) stack.append(res) if op == "&": return all(stack),i+1 elif op == "|": return any(stack),i+1 return not stack[0],i+1 ob = Solution() print(ob.parseBoolExpr("|(!(t),&(t,f,t))"))
Python: парсинг логической строки в список списков
Я получаю строку логических выражений из базы данных, и мне нужно поместить их в список списков для дальнейшей оценки. Я уже много читал о разборе строк, но пока не смог найти ответ. Для облегчения понимания проблемы, вот 3 примера:
input_string1 = '((A OR B) AND (C OR D)) OR E' input_string2 = '(A AND ( B OR C ) AND D AND E)' input_string3 = ' A OR ( B AND C ) OR D OR E'
Results_string1=[ ['A', 'C'], ['A','D'], ['B','C'], ['B','D'], ['E']] Results_string2=[ ['A', 'B', 'D', 'E'], ['A', 'C', 'D', 'E'] ] Results_string3=[ ['A'], ['B','C'], ['D'], ['E'] ]
Так что в основном мне нужны полностью факторизованные выражения в терминах OR и помещать их в список. Это означает, что любое условие AND выражается наличием обоих выражений в одном и том же sublist , тогда как любое условие OR запускает создание новых подсписков.
e.g. E AND F --> [E, F], E OR F --> [[E],[F]]
Строки из базы данных имеют произвольную длину и произвольное количество скобок.
У любого есть идея, как определить грамматику, чтобы я мог использовать, например, пакет pyparsing?
import pyparsing as pp gene_id = pp.Word(pp.alphanums) logical = ( pp.Keyword("AND") | pp.Keyword("OR") ).setName("logical") l_brackets = (pp.Literal('(') ).setName('l_brackets') r_brackets = ( pp.Literal(')') ).setName('r_brackets')
Но как мне определить настоящий парсер?
Одна из основных проблем заключается в том, что я не знаю, как обрабатывать произвольные скобки и длину строки. Я играл с nestedExpr()-parser из набора инструментов pyparser , но пока не смог создать правильное поведение.