Калькулятор выражений
Три дня в перерывах между работой, сном и ничегонеделаньем, я осуществлял свою давнюю задумку. А именно писал калькулятор для математических выражений. Первая бета уже готова и я буду очень благодарен если кто ее захочет потестить =)
Программа работает, хотя не уверен, что вычесал из нее все баги. К тому же я наплевательски отнесся к проверке ошибок в выражении и обработке исключительных ситуаций. Надеюсь, что решу эту проблему в ближайшем будущем. Хотя здесь возможны довольно серьезные изменения в коде, потому как сразу все продумать в подробностях я ,как всегда, не удосужился :[
Кратко опишу алгоритм работы.
Выражение, которое нужно вычислить приводится к нормальному виду. Для этого из него удаляются все пробелы, все переводится в верхний регистр, а потом математические операторы в строке заменяются на семантику, используемую в программе. Последнее действие необходимо, т.к. применен в своем роде полиморфизм (абстракция оператора), а необходимый дочерний класс выбирается по имени. Кроме того, при замене вокруг операторов выставляется нужное число пробелов (см. renameArray), которые дальше используются при парсинге строки.
Функция-вычислитель calculateSimpleExpression() работает следующим образом. В цикле производится поиск наиболее приоритетного оператора в выражении. Если приоритет нескольких операторов одинаков, то выбирается тот, который встречается первым (слева-направо). Если операторов не найдено, цикл завершается и функция возвращает вычисленное значение. После того, как определен оператор, определяются левый и правый операнды. После создается объект Operator, соответствующего класса, для которого вызывается метод calculate(). Оператор с операндами в строке заменяются на результат вычисления.
Для вычисления выражений со скобками используется рекурсивная функция calculateExpression(). Она по восходящей раскрывает скобки (от внутренних к внешним), вычисляя выражения в скобках и заменяя скобки результатом.
Пусть программа и корявая немного, но она работает и написал я ее сам, чем, собственно, и доволен. Думаю позже я приведу ее в более пристойный вид. Буду благодарен за конструктивную критику и нормативные высказывания по поводу этого творения :]
/**
* @author Yuriy S. Sokirskiy
*/
package org.x82.formula.main;
public final class Main {
private static final String[][] renameArray = { { "\\+", " Plus " },
{ "\\-", " Minus " }, { "\\*", " Mult " }, { "\\/", " Div " },
{ "SQRT", "Sqrt " }, { "SIN", "Sin " }, { "COS", "Cos " },
{ "TG", "Tan " }, { "CTG", "Ctan " }, { "\\^", " Pow " } };
private static final String[][] priorityArray = { { "Plus", "Minus" },
{ "Mult", "Div" }, { "Sqrt", "Sin", "Cos", "Tan", "Ctan" },
{ "Pow" } };
// Рекурсивный метод, который собственно и вычисляет значение выражений
public static String calculateExpression(String expressionString) {
// Проверяем есть ли в выражении скобки
if (checkBrackets(expressionString)) {
String tempExpressionString = getExpressionBetweenBrackets(expressionString);
// System.out.println(tempExpressionString);
// Заменяем скобки на значение вычисленное данной функцией
expressionString = expressionString.replaceAll("\\("
+ tempExpressionString + "\\)",
calculateExpression(tempExpressionString));
}
if (checkBrackets(expressionString))
return calculateExpression(expressionString);
else
return calculateSimpleExpression(expressionString);
}
// Подготовка строки к обработке
private static String prepareString(String expressionString) {
expressionString = expressionString.replaceAll(" ", "");
expressionString = expressionString.toUpperCase();
for (int i = 0; i < renameArray.length; i++) {
expressionString = expressionString.replaceAll(renameArray[i][0],
renameArray[i][1]);
}
return expressionString;
}
// Проверка парности скобок
public static boolean checkPairBrackets(String expressionString) {
int forw, back;
forw = 0;
back = 0;
for (int i = 0; i < expressionString.length(); i++) {
if (expressionString.charAt(i) == '(')
forw++;
if (expressionString.charAt(i) == ')')
back++;
}
if (forw == back)
return true;
else
return false;
}
// Проверка наличия скобок
public static boolean checkBrackets(String expressionString) {
if (expressionString.indexOf('(') != -1)
return true;
else
return false;
}
// Получаем выражение между последними внутренними скобками
public static String getExpressionBetweenBrackets(String expressionString) {
int from = expressionString.lastIndexOf('(');
int to = expressionString.indexOf(')', from);
return expressionString.substring(from + 1, to);
}
// Вычисление простого выражения (без скобок)
public static String calculateSimpleExpression(String expressionString) {
// Флаг для индикации окончания вычисления простого выражения
boolean calculatingFlag = true;
// Цикл обработки
while (calculatingFlag) {
int priority = -1;
int op_number = -1;
// Нахождение в строке наиболее приоритетного оператора
// Для операторов с одинаковым приоритетом определяется первый по
// порядку слева
for (int i = 0; i < priorityArray.length; i++)
for (int j = 0; j < priorityArray[i].length; j++)
if (expressionString.indexOf(priorityArray[i][j]) != -1) {
if (i > priority) {
priority = i;
op_number = j;
} else if ((i == priority)
&& (expressionString
.indexOf(priorityArray[i][j]) < expressionString
.indexOf(priorityArray[i][op_number]))) {
op_number = j;
}
}
// Если был найден оператор
if (priority != -1) {
// Позиция оператора в выражении
int op_position = expressionString
.indexOf(priorityArray[priority][op_number]);
// Переменные позиций операндов
int left_start_index = 0;
int right_start_index = 0;
int left_end_index = 0;
int right_end_index = 0;
// Определение левого операнда
String leftOperand = "0";
if (op_position != 0) {
left_start_index = 0;
left_end_index = op_position - 1;
while (expressionString.indexOf(" ", left_start_index) != left_end_index) {
left_start_index = expressionString.indexOf(" ",
left_start_index) + 1;
}
leftOperand = expressionString.substring(left_start_index,
left_end_index);
}
// Определение правого операнда
right_start_index = expressionString.indexOf(" ", op_position) + 1;
right_end_index = expressionString.length();
if (expressionString.indexOf(" ", right_start_index) != -1)
right_end_index = expressionString.indexOf(" ",
right_start_index);
String rightOperand = expressionString.substring(
right_start_index, right_end_index);
// Для операции унарного минуса присваиваем левому операнду
// значение "0"
if ((priorityArray[priority][op_number].equals("Minus"))
&& (op_position == 1))
leftOperand = "0";
// System.out.println(leftOperand + " "
// + priorityArray[priority][op_number] + " "
// + rightOperand);
try {
// Создаем объект Operator соответствующий текущей операции
Operator op = (Operator) Class.forName(
"org.x82.formula.operators."
+ priorityArray[priority][op_number])
.newInstance();
// Для операторов с приоритетом 2 заменяем только оператор и
// правый операнд, т.к. левого операнда у них нет
if (priority != 2)
expressionString = expressionString.replaceFirst(
expressionString.substring(left_start_index,
right_end_index), op.calculate(
leftOperand, rightOperand));
else
expressionString = expressionString.replaceFirst(
expressionString.substring(op_position,
right_end_index), op.calculate(
leftOperand, rightOperand));
} catch (Exception e) {
e.printStackTrace();
}
} else
calculatingFlag = false;
}
return expressionString;
}
}
Разделы:
Архив блога:
Я читаю:
Моя матрица:
Контакты:
0 комментарий(я,ев):
Отправить комментарий