-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
1 task #346
base: master
Are you sure you want to change the base?
1 task #346
Changes from 6 commits
d449e5f
605a5a4
ed20414
251fdf2
820b723
1f82f19
a152601
6069427
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<parent> | ||
<artifactId>mipt-java-2016</artifactId> | ||
<groupId>ru.mipt.java2016</groupId> | ||
<version>1.0.0</version> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>homework-g596-narsia</artifactId> | ||
<dependencies> | ||
<dependency> | ||
<groupId>ru.mipt.java2016</groupId> | ||
<artifactId>homework-base</artifactId> | ||
<version>1.0.0</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>ru.mipt.java2016</groupId> | ||
<artifactId>homework-tests</artifactId> | ||
<version>1.0.0</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
|
||
</project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,359 @@ | ||
package ru.mipt.java2016.homework.g596.narsia.task1; | ||
|
||
import ru.mipt.java2016.homework.base.task1.Calculator; | ||
import ru.mipt.java2016.homework.base.task1.ParsingException; | ||
|
||
import java.util.*; | ||
|
||
// подробное описание работы кода | ||
// можно найти в файле description | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Пиши комментарии прямо в коде |
||
|
||
|
||
public class MyCalculator implements Calculator { | ||
private enum SymbolType { DIGIT, POINT, USUAL_OPERATOR, MINUS, SPACE, | ||
OPENING_BRACKET, CLOSING_BRACKET, FIRST, INVALID } | ||
|
||
|
||
private SymbolType whatIsIt(Character symbol) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Не слишком-то похоже на понятное название |
||
if (Character.isDigit(symbol)) { | ||
return SymbolType.DIGIT; | ||
} | ||
if (symbol.equals('.')) { | ||
return SymbolType.POINT; | ||
} | ||
if ((symbol.equals('+')) || (symbol.equals('*')) || (symbol.equals('/'))) { | ||
return SymbolType.USUAL_OPERATOR; | ||
} | ||
if (symbol.equals('-')) { | ||
return SymbolType.MINUS; | ||
} | ||
if (Character.isWhitespace(symbol)) { | ||
return SymbolType.SPACE; | ||
} | ||
if (symbol.equals('(')) { | ||
return SymbolType.OPENING_BRACKET; | ||
} | ||
if (symbol.equals(')')) { | ||
return SymbolType.CLOSING_BRACKET; | ||
} | ||
if (symbol.equals('~')) { | ||
return SymbolType.FIRST; | ||
} | ||
return SymbolType.INVALID; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Во многих языках программирования есть такая штука, как assert. Его используют, чтобы поймать некорректные состояния. Этот твой |
||
} | ||
|
||
|
||
private void isAlmostValid(String expression) throws ParsingException { | ||
if (expression == null) { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
char prevSymbol = '~'; | ||
char curSymbol; | ||
char importantPrevSymbol = '~'; | ||
boolean pointFlag = false; | ||
boolean spaceFlag = false; | ||
|
||
for (int index = 0; index < expression.length(); ++index) { | ||
curSymbol = expression.charAt(index); | ||
switch (whatIsIt(curSymbol)) { | ||
case DIGIT: | ||
if (whatIsIt(prevSymbol) == SymbolType.SPACE) { | ||
if ((whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) || | ||
(whatIsIt(importantPrevSymbol) == SymbolType.CLOSING_BRACKET)) { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
} | ||
if (whatIsIt(prevSymbol) == SymbolType.CLOSING_BRACKET) { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
break; | ||
|
||
case POINT: | ||
if (whatIsIt(prevSymbol) == SymbolType.DIGIT) { | ||
if (!pointFlag) { | ||
pointFlag = true; | ||
} else { | ||
throw new ParsingException("2 points in one number"); | ||
} | ||
} else { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
break; | ||
|
||
case USUAL_OPERATOR: | ||
if ((whatIsIt(importantPrevSymbol) == SymbolType.USUAL_OPERATOR) || | ||
(importantPrevSymbol == '(') || (importantPrevSymbol == '~') || | ||
(importantPrevSymbol == '.')) { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
if (whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) { | ||
pointFlag = false; | ||
} | ||
break; | ||
|
||
case MINUS: | ||
if (importantPrevSymbol == '.') { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
if (whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) { | ||
pointFlag = false; | ||
} | ||
break; | ||
|
||
case SPACE: | ||
if (prevSymbol == '.') { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
if (whatIsIt(prevSymbol) == SymbolType.DIGIT) { | ||
pointFlag = false; | ||
} | ||
break; | ||
|
||
case OPENING_BRACKET: | ||
if ((whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) || | ||
(importantPrevSymbol == '.') || (importantPrevSymbol == ')')) { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
break; | ||
|
||
case CLOSING_BRACKET: | ||
if (whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) { | ||
pointFlag = false; | ||
} | ||
if ((importantPrevSymbol == '.') || (importantPrevSymbol == '(') || | ||
(importantPrevSymbol == '~') || | ||
(whatIsIt(importantPrevSymbol) == SymbolType.USUAL_OPERATOR) || | ||
(importantPrevSymbol == '-')) { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
break; | ||
|
||
default: | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
prevSymbol = curSymbol; | ||
if (whatIsIt(curSymbol) != SymbolType.SPACE) { | ||
importantPrevSymbol = curSymbol; | ||
spaceFlag = true; | ||
} | ||
} | ||
if (!spaceFlag) { | ||
throw new ParsingException("Invalid expression"); | ||
} | ||
} | ||
|
||
|
||
private String removeSpaces(String expression) { | ||
StringBuilder result = new StringBuilder(expression.length()); | ||
for (int index = 0; index < expression.length(); ++index) { | ||
if (!Character.isWhitespace(expression.charAt(index))) { | ||
result.append(expression.charAt(index)); | ||
} | ||
} | ||
return result.toString(); | ||
} | ||
|
||
|
||
private String removeUnaryMinuses(String expressionWithoutSpaces) { | ||
expressionWithoutSpaces = expressionWithoutSpaces.concat("~"); | ||
StringBuilder result = new StringBuilder(expressionWithoutSpaces.length()); | ||
boolean bracketFlag = false; | ||
for (int index = 0; index < expressionWithoutSpaces.length(); ++index) { | ||
if (expressionWithoutSpaces.charAt(index) == '-') { | ||
if (index == 0) { | ||
result.append('0'); | ||
} else { | ||
switch (whatIsIt(expressionWithoutSpaces.charAt(index - 1))) { | ||
case OPENING_BRACKET: | ||
result.append("0-"); | ||
continue; | ||
case USUAL_OPERATOR: | ||
case MINUS: | ||
result.append("(0-"); | ||
bracketFlag = true; | ||
continue; | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
if ((!Character.isDigit(expressionWithoutSpaces.charAt(index))) && | ||
(expressionWithoutSpaces.charAt(index) != '.') && (index > 0) && (bracketFlag)) { | ||
result.append(")"); | ||
bracketFlag = false; | ||
} | ||
if (expressionWithoutSpaces.charAt(index) != '~') { | ||
result.append(expressionWithoutSpaces.charAt(index)); | ||
} | ||
} | ||
return result.toString(); | ||
} | ||
|
||
|
||
private int getCode(char first, char second) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Как говорили Великие:
Почему не сделать enum вместо цифр? С ним назначение функции слегка прояснится. Заодно можно будет переименовать |
||
switch (first) { | ||
case '~': | ||
if ((whatIsIt(second) == SymbolType.USUAL_OPERATOR) || | ||
(second == '-') || (second == '(')) { | ||
return 1; | ||
} | ||
if (second == '~') { | ||
return 4; | ||
} | ||
if (second == ')') { | ||
return 5; | ||
} | ||
case '+': | ||
case '-': | ||
if ((second == '*') || (second == '/') || (second == '(')) { | ||
return 1; | ||
} | ||
if ((second == '~') || (second == ')') || | ||
(second == '+') || (second == '-')) { | ||
return 2; | ||
} | ||
case '*': | ||
case '/': | ||
if (second == '(') { | ||
return 1; | ||
} | ||
if ((second == '~') || (second == ')') || | ||
(whatIsIt(second) == SymbolType.USUAL_OPERATOR) || | ||
(second == '-')) { | ||
return 2; | ||
} | ||
case '(': | ||
if ((second == '(') || (whatIsIt(second) == SymbolType.USUAL_OPERATOR) || | ||
second == '-') { | ||
return 1; | ||
} | ||
if (second == ')') { | ||
return 3; | ||
} | ||
if (second == '~') { | ||
return 5; | ||
} | ||
default: | ||
return -1; | ||
} | ||
} | ||
|
||
|
||
private String getRPN(String expression) throws ParsingException { | ||
expression = expression.concat("~"); | ||
Character curSymbol; | ||
Character prevSymbol = '~'; | ||
Stack<Character> texas = new Stack<>(); | ||
StringBuilder california = new StringBuilder(expression.length()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. То, что в статье, которую ты скинул, есть слова Техас и Калифорния, ещё не значит, что их нужно использовать, как названия переменных. Придумай что-нибудь более говорящее |
||
texas.push('~'); | ||
|
||
int index = 0; | ||
while (true) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Как интересно ты в исходном решении заменил |
||
curSymbol = expression.charAt(index); | ||
if (index > 0) { | ||
prevSymbol = expression.charAt(index - 1); | ||
} | ||
switch (whatIsIt(curSymbol)) { | ||
case DIGIT: | ||
case POINT: | ||
if ((Character.isDigit(prevSymbol)) || (prevSymbol == '.') || | ||
(prevSymbol == '~')) { | ||
california.append(curSymbol); | ||
++index; | ||
} else { | ||
california.append(" "); | ||
california.append(curSymbol); | ||
++index; | ||
break; | ||
} | ||
continue; | ||
|
||
default: | ||
break; | ||
} | ||
|
||
switch (getCode(texas.peek(), curSymbol)) { | ||
case 1: | ||
texas.push(curSymbol); | ||
++index; | ||
break; | ||
case 2: | ||
california.append(" "); | ||
california.append(texas.peek()); | ||
texas.pop(); | ||
break; | ||
case 3: | ||
texas.pop(); | ||
++index; | ||
break; | ||
case 4: | ||
return california.toString(); | ||
case 5: | ||
throw new ParsingException("Invalid bracket balance"); | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
|
||
|
||
private double doOperation(double first, double second, char operator) { | ||
switch (operator) { | ||
case '+': | ||
return first + second; | ||
case '-': | ||
//сейчас будет костыль | ||
if ((first == 0) && (second == 0)) { | ||
return -0.0; | ||
} | ||
return first - second; | ||
case '*': | ||
return first * second; | ||
case '/': | ||
return first / second; | ||
default: | ||
return -1.0; | ||
} | ||
} | ||
|
||
|
||
@Override | ||
public double calculate(String expression) throws ParsingException { | ||
isAlmostValid(expression); | ||
String withoutSpaces = removeSpaces(expression); | ||
String withoutSpacesAndUnaryMinuses = removeUnaryMinuses(withoutSpaces); | ||
String rpn = getRPN(withoutSpacesAndUnaryMinuses); | ||
Stack<Double> numbers = new Stack<>(); | ||
Double first; | ||
Double second; | ||
StringBuilder curNumber = new StringBuilder(); | ||
char curChar = '~'; | ||
char prevChar; | ||
for (int cnt = 0; cnt < rpn.length(); ++cnt) { | ||
prevChar = curChar; | ||
curChar = rpn.charAt(cnt); | ||
switch (whatIsIt(curChar)) { | ||
case DIGIT: | ||
case POINT: | ||
curNumber.append(curChar); | ||
break; | ||
case USUAL_OPERATOR: | ||
case MINUS: | ||
second = numbers.peek(); | ||
numbers.pop(); | ||
first = numbers.peek(); | ||
numbers.pop(); | ||
numbers.push(doOperation(first, second, curChar)); | ||
break; | ||
case SPACE: | ||
if (Character.isDigit(prevChar)) { | ||
numbers.push(Double.parseDouble(curNumber.toString())); | ||
curNumber.delete(0, curNumber.length()); | ||
} | ||
default: | ||
break; | ||
} | ||
} | ||
return numbers.peek(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Считается плохим тоном импортировать через *. Перечисли всё, что ты импортируешь отдельно