Java - разбор многочлена с комплексными коэффициентами с регулярным выражением

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

(соответствующий код внизу сообщения)

Полиномы, которые я хочу разобрать, имеют следующий вид:

  1. Коэффициент может быть действительным, мнимым или комплексным.
  2. Если коэффициент сложный, он будет заключен в круглые скобки. Если эти скобки являются ведущим коэффициентом, им не будет предшествовать + или -.
  3. Если коэффициент действительный, мнимый или комплексный, действительные и/или мнимые компоненты которого имеют величину 1, 1 не появится, а только знак.
  4. Перед скобками может стоять только +.
  5. Переменная x может иметь степень (>2), может иметь степень 1, и тогда она появляется так же, как x, или может вообще не появляться.
  6. Больше нет правил относительно текстового представления многочлена, т.е. степени не обязательно упорядочены по возрастанию\убыванию.

Некоторые примеры правильно отформатированных полиномов:

  • 1
  • -1
  • -2.1x
  • 3i
  • x^2-1
  • -x^3+2x+1
  • (5-5i)x^2-x-1
  • (-1+i)x-5
  • -ix^3-x^2+1

..и некоторые плохо отформатированные:

  • 1x (ведущий ненужный 1)
  • +(+1-2i)x (скобки имеют ведущий +, реальный компонент имеет ведущий +)
  • (5.1i)x^2 (круглые скобки не нужны, так как коэффициент мнимый)
  • -(i-1) (в начале комплексного коэффициента стоит -)

После некоторого чтения в Интернете (SO, учебные пособия по Java, Java API) я быстро пришел к выводу, что регулярное выражение было бы самым простым подходом для синтаксического анализа, учитывая все ограничения, упомянутые выше. С формальной стороны возможно регулярное выражение для этой задачи, поскольку я нарисовал NFA, который принимает только такие допустимые выражения.

Я делаю этот TDD (через JUnit 4), и этот тест не проходит:

assertEquals("Polynomial parsed incorrectly.", poly07, PolyParser.parse(exp07));

где poly07 выглядит так: (5-5i)x^2-x-1.

Это исключение, которое возникает:

java.lang.NumberFormatException: For input string: "5-5"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at PolyParser.parse(PolyParser.java:55)
at PolyParserTest.testParse(PolyParserTest.java:59)

Я пытался выполнить отладку и увидел, что регулярное выражение захватывает 5-5i (а позже удаляет i). Затем он пытается вызвать Double.parseDouble со строкой аргумента 5-5, что вызывает исключение.

После всего прочтения я не могу понять, что нужно изменить в регулярном выражении, чтобы все это шоу работало. Кроме того, регулярное выражение не упорядочено, как упомянутые выше ограничения представлений, потому что я хочу увидеть, является ли коэффициент сложным, прежде чем пытаться проанализировать его как реальный; также столкнулись с проблемами, когда действительные числа (т.е. с десятичной точкой) анализируются как целые числа, поэтому регулярное выражение сначала обрабатывает действительные числа.

Регулярное выражение:

public static final String POLYNOMIAL_REGEX =
        "([+-])?" +                     // leading plus or minus
        "(\\()?" +                      // parenthesis to denote the beginning of a complex number
        "([+-])?(((\\d+.\\d+)|\\d+)i)?" +      // component of coefficient, imaginary
        "(((-)?\\d+.\\d+)|\\d+)?" +     // component of coefficient, real
        "(\\))?" +                      // parenthesis to denote the end of a complex number
        "(x)?" +                        // variable
        "(?:\\^(\\d+))?";               // power of the variable

Я не собираюсь публиковать здесь весь соответствующий код, потому что это загромождает вещи. Весь код находится на GitHub, только не забудьте переключиться на ветку PolyParser.

Соответствующий код находится в файлах:

  1. PolyParser.java
  2. Polynomial.java
  3. Complex.java

Тестовый модуль находится в файле PolyParserTest.java.


person asafc    schedule 29.09.2015    source источник
comment
регулярные выражения почти никогда не являются правильным решением для анализа проблем.   -  person Henry    schedule 29.09.2015
comment
Мой совет: не надо. Используйте контекстно-независимый синтаксический анализатор, если вам нужен простой, взгляните на PEP. Или вы можете пойти на все и использовать что-то вроде Antlr.   -  person biziclop    schedule 29.09.2015
comment
Кроме того, вы можете попробовать JEP. , который делает все это из коробки, и вы даже можете сразу вычислить полиномы.   -  person biziclop    schedule 29.09.2015
comment
Сначала вы определитесь, что вам нужно сделать. А затем вы выбираете необходимые инструменты для этого. В этом случае вы сначала выбрали инструмент... и он оказался неправильным.   -  person Cedric Mamo    schedule 29.09.2015


Ответы (1)


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

Однако выражения довольно легко анализировать, используя нисходящий анализ. См. мой ответ о том, как это сделать: https://stackoverflow.com/a/2336769/120163 Этот ответ описывает, как для простого синтаксического анализа и связан с другим ответом, в котором рассказывается о том, как создать AST для представления вашего выражения.

Первый шаг: напишите грамматику, представляющую то, что позволяют ваши выражения. В вашем вопросе есть специальное описание, но грамматика заставит вас точно написать, что является законным, а что нет. С помощью этой грамматики вы можете довольно легко написать парсер рекурсивного спуска, предложенный выше.

person Ira Baxter    schedule 29.09.2015
comment
Давайте предположим, что пользователь вводит правильно отформатированные выражения, и мы отказываемся от защитного программирования. Таким образом, нет вложенных скобок. Я использую регулярное выражение и его группы захвата в качестве синтаксического анализатора. Просто кажется, что очень много исследований и работы по реализации синтаксического анализатора с нуля, когда у меня есть регулярное выражение, которое работает почти так, как я хочу, просто не хватает тонкой настройки. Твои мысли? - person asafc; 29.09.2015
comment
Ваши пользователи будут делать ошибки при вводе формул. Они будут ожидать круглых скобок, нравится вам это или нет. Вам нужен надежный синтаксический анализатор. - person Ira Baxter; 29.09.2015