За последние 24 часа нас посетили 21692 программиста и 1036 роботов. Сейчас ищут 716 программистов ...

Шаблон парсящий выражение в скобках с вложенными скобками

Тема в разделе "Регулярные выражения", создана пользователем Познающий php, 6 апр 2017.

  1. Познающий php

    Познающий php Новичок

    С нами с:
    23 мар 2017
    Сообщения:
    381
    Симпатии:
    74
    Всем мой пламенный шалом. Я пытаюсь парсить математические выражения, которые перевожу в вид для исполнения на php. И вот встречается такое, например, "50-10%"
    Для парсинга такой код
    PHP:
    1. $text = preg_replace('/(\d+)[+-](\d+)\%/', \1*\2/100)', $text);
    Вполне вроде рабочий. Но вот беда, что может встретится такое выражение, например "(1+(1+3)*10)-10%"
    Как такое запарсить, если учесть что вложенных скобок может быть сколько угодно?
     
  2. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Выражения не парсятся регулярками. Читайте про обратную польскую нотацию, к примеру. В сети можно найти алгоритмы и перевода выражения к обратной польской нотации, и вычисления выражения, записанного в обратной польской нотации.
    --- Добавлено ---
    Есть и другие подходы - к примеру, прямая польская нотация, но насколько с ВУЗа помню, в обратной польке считать проще.
     
    denis01 нравится это.
  3. Познающий php

    Познающий php Новичок

    С нами с:
    23 мар 2017
    Сообщения:
    381
    Симпатии:
    74
    Я читал про нее конечно когда думал как все это парсить, но я, честно говоря, так и не понял, как она поможет мне решать уравнения с переменной. Хотел поискать примеры, но они либо на C++ и мне почти не понятны, либо слишком банальные на простой арифметике (2+2)*3
     
  4. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.230
    Симпатии:
    1.715
    Адрес:
    Молдова, г.Кишинёв
  5. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Ну так какая задача: разобрать выражение или решить произвольное уравнение с одной переменной?
    --- Добавлено ---
    Для всего существуют свои методы. К примеру, системы линейных уравнений решаются методом моего однофамильца Крамера. Алгоритм решения произвольных уравнений наверняка существует, поскольку такие программы есть, но мне не известен (может, я до него не дожил в ВУЗе, который не закончил)
     
  6. Познающий php

    Познающий php Новичок

    С нами с:
    23 мар 2017
    Сообщения:
    381
    Симпатии:
    74
    Ну я парсю для чего? чтобы решить! :) Я их разбираю и перевожу в вид для исполнения php. пользователь вводит типа 8*20%-(34+6)+3^2 - перевожу в 8*0,2-(34+6)+pow(3,2) и ему ответ.
    Уже наговнокодил с регулярками и работает, правда с некоторыми оговорками ;)
    Дальше хочу расширить для решений типа 2+5x=10+x или 2^x=8
     
  7. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Это две совершенно разные задачи. Первая полностью решается с помощью обратной польки. Идея перевести в синтаксис php и прогнать через eval мне не сильно нравится (потому что я не люблю eval), хотя может быть и можно.
    Универсальный решатель уравнений - это несколько совсем иное. Если только линейные уравнения и только квадратные - это одно. Если произвольные - там сложный алгоритм, поскольку тут уже вступает. Ну первое уравнение решается на раз два, второе тоже, но если тебе вводят произвольное уравнение, тут уже надо придумывать что-то супер-универсальное, без кучи условий типа "если это линейное уравнение, то так, если квадратное - то так, если степенное - то вот эдак. Тебе же вполне могут ввести 2^x + x^2 + sin(x/2) = 14. Это я от балды, поэтому решения не знаю, но это уравнение тоже может теоретически иметь корни.
    --- Добавлено ---
    Тут нужно подтягивать соответствующий математический аппарат, типа http://yandex.ru/clck/jsredir?from=...0n=ru&cts=1491583587842&mc=4.1867043459100275
     
  8. Познающий php

    Познающий php Новичок

    С нами с:
    23 мар 2017
    Сообщения:
    381
    Симпатии:
    74
    Сложное не потяну, на данный момент задача покрыть банальные примеры из курса средней школы: арифметика и простые уравнения с одной переменной. Сейчас бы просто арифметику отладить.

    Собственно говоря вместо польской записи, 3 строчки года с регуляркой и эвал. Мне кажется у меня проще. Единственное не могу решать, как применять степень и вычитание процентов к скобкам - ну собственно сама тема этому посвящена. Остальное все работает :p


    С eval все в норме - перед этим все разбирается, так что лишний код туда не пойдет точно.
     
  9. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Ну если говорить про eval, то со степенью проблем не должно быть - начиная с php 5.6 у нас есть оператор **, а пользоваться сейчас чем-то меньшим для новых проектов - глупость. Так что можно просто заменять уголок на двойную звёздочку банальным str_replace. С процентами да, сложнее. Думать надо. Можно попробовать preg_replace_callback
     
    Познающий php нравится это.
  10. Познающий php

    Познающий php Новичок

    С нами с:
    23 мар 2017
    Сообщения:
    381
    Симпатии:
    74
    Вот за такое спасибо. А то я сам чет тупил, когда читал документацию, даже не обратил внимание на ** :confused:
    А с процентами что-то тоже тупил - решил -+ процент менять на умножение. "-50%" на "*0,5" на "+50" на "*1,5" Вроде норм, хотя может еще что всплывет... :rolleyes:

    И все таки получается регулярками парсить математические выражения проще, чем делать обратную польскую запись :cool:

    PHP:
    1.  $text = '(55-50)^2+√(9)' //входная строка
    2. $patterns = array ('/\^/' ,'/√\((\d+[.]{0,1}[\d]{0,})\)/'); // расширяем на все условия
    3. $replace = array ('**','sqrt(\1)'); // расширяем на все условия
    4. $text = preg_replace($patterns, $replace, $text);
    5. eval();
    Вместо кучи кода перегона из стеки в стеки операторов и операндов...
     
    #10 Познающий php, 8 апр 2017
    Последнее редактирование: 8 апр 2017
  11. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Ну если считаешь допустимым использовать eval, то проще :)