forked from hummel/PR1-Spreadsheet
Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Oliver Hummel | ada8f538a2 |
|
@ -1,11 +1,4 @@
|
||||||
1,5,=SUMME(A1:B4),,,,,,,,200
|
1,2
|
||||||
2,6,,,,,,,,,
|
3,4
|
||||||
3,7,,,,,,,,,
|
5,6
|
||||||
4,8,,=1+4*A2,,,2,,,4,
|
7,8
|
||||||
,,,,,3,3,,,,
|
|
||||||
,,,,,,,,,,
|
|
||||||
,,,,,,,,,,
|
|
||||||
,,,,,,,,,,
|
|
||||||
,,,,,,,,,,
|
|
||||||
,,,,,,,,69,,
|
|
||||||
,,,,,,,=STABW(K1:K11),,,100
|
|
||||||
|
|
|
|
@ -1,408 +1,29 @@
|
||||||
package de.hs_mannheim.informatik.spreadsheet;
|
package de.hs_mannheim.informatik.spreadsheet;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Scanner;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Part of a simplified spreadsheet system for the PR1 programming lab at Hochschule Mannheim.
|
* Part of a simplified spreadsheet system for the PR1 programming lab at Hochschule Mannheim.
|
||||||
*
|
*
|
||||||
* @author Oliver Hummel & Victor Waitz
|
* @author Oliver Hummel
|
||||||
*/
|
*/
|
||||||
public class Axel {
|
public class Axel {
|
||||||
static Scanner keyboard = new Scanner(System.in);
|
|
||||||
static Spreadsheet spr = new Spreadsheet(11, 11);
|
|
||||||
static String saveFilePath = "Axel\\resources\\zahlen.csv";
|
|
||||||
|
|
||||||
public static void main(String[] args) throws FileNotFoundException {
|
public static void main(String[] args) throws FileNotFoundException {
|
||||||
System.out.println("Welcome to Axel (Totally not Excel)");
|
Spreadsheet spr = new Spreadsheet(10,10);
|
||||||
System.out.println();
|
|
||||||
|
spr.put("A3", "123");
|
||||||
spr.loadSpecialTable();
|
spr.put("A2", "1");
|
||||||
|
|
||||||
|
spr.put("B9", "=41+A2");
|
||||||
|
spr.put("J5", "=7*6");
|
||||||
|
spr.put("J6", "=3/2");
|
||||||
|
|
||||||
System.out.println(spr);
|
System.out.println(spr);
|
||||||
|
|
||||||
// spr.saveCsv("/tmp/test.csv");
|
spr.saveCsv("/tmp/test.csv");
|
||||||
|
|
||||||
while (true) {
|
// TODO: You might want to put "UI loop" for entering value and formulas here resp. in some UI methods.
|
||||||
String userCommandPositionInput = userCommandPositionInput();
|
|
||||||
if (userCommandPositionInput.charAt(0) == '*') {
|
|
||||||
executeCommand(userCommandPositionInput);
|
|
||||||
System.out.println(spr);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String userPositionInput = userCommandPositionInput;
|
|
||||||
|
|
||||||
String userValueFormulaInput = userValueFormulaInput(userPositionInput);
|
|
||||||
|
|
||||||
spr.put(userPositionInput, userValueFormulaInput);
|
|
||||||
|
|
||||||
System.out.println(spr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//? User input for a program command or a position
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prompts the user to input a command for the program or a position.
|
|
||||||
* May be called multiple times, if the input is faulty.
|
|
||||||
* @return The user inputted position or command as a string.
|
|
||||||
*/
|
|
||||||
public static String userCommandPositionInput() {
|
|
||||||
System.out.println();
|
|
||||||
System.out.println("Input a command for the program or a position");
|
|
||||||
System.out.printf("List of program commands: *clear, *load, *save, *exit or *help %nFormat for position: A1 or B14%n");
|
|
||||||
System.out.print("Input: ");
|
|
||||||
String userCommandPositionInput = keyboard.nextLine();
|
|
||||||
|
|
||||||
return userCommandPositionComputation(userCommandPositionInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* First method in the error check chain for the user input for a command or a position.
|
|
||||||
* This method may call userCommandPositionInput() again, if the input is faulty.
|
|
||||||
* Checks if the input is empty and if not decides if the input is a command or a position.
|
|
||||||
* Calls different methods to check for different errors.
|
|
||||||
* @param userCommandPositionInput The user inputted position or command as a string.
|
|
||||||
* @return The user inputted position or command as a string.
|
|
||||||
*/
|
|
||||||
public static String userCommandPositionComputation(String userCommandPositionInput) {
|
|
||||||
|
|
||||||
if (userCommandPositionInput.isEmpty()) {
|
|
||||||
System.out.println("Input is empty!");
|
|
||||||
return userCommandPositionInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
//? Program command
|
|
||||||
if (userCommandPositionInput.charAt(0) == '*') {
|
|
||||||
if (!(userCommandErrorCheck(userCommandPositionInput))) {
|
|
||||||
System.out.println("Invalid command!");
|
|
||||||
return userCommandPositionInput();
|
|
||||||
}
|
|
||||||
return userCommandPositionInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
//? Position
|
|
||||||
if (!(userPositionErrorCheck(userCommandPositionInput, spr))) {
|
|
||||||
System.out.println("Invalid position!");
|
|
||||||
return userCommandPositionInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(userPositionBoundsErrorCheck(userCommandPositionInput, spr))) {
|
|
||||||
System.out.println("Position out of bounds!");
|
|
||||||
return userCommandPositionInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
return userCommandPositionInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the user inputted command is valid.
|
|
||||||
* Simply checks if the input equals one of the program commands.
|
|
||||||
* Case does not matter.
|
|
||||||
* @param CommandToCheck The user inputted command as a string.
|
|
||||||
* @return true if the command is valid, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean userCommandErrorCheck(String CommandToCheck) {
|
|
||||||
//? true if valid
|
|
||||||
//? valid inputs are: *clear, *exit, *save, *load, *help (and all upper case variants)
|
|
||||||
|
|
||||||
CommandToCheck = CommandToCheck.toLowerCase();
|
|
||||||
if (CommandToCheck.equals("*clear") || CommandToCheck.equals("*exit") || CommandToCheck.equals("*save") || CommandToCheck.equals("*load") || CommandToCheck.equals("*help")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the user inputted position is valid.
|
|
||||||
* Checks if the input is the right length and if it is in the right format.
|
|
||||||
* Case does not matter.
|
|
||||||
* @param positionToCheck The user inputted position as a string.
|
|
||||||
* @param spr The spreadsheet object. (This input is needed for tests)
|
|
||||||
* @return true if the position is valid, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean userPositionErrorCheck(String positionToCheck, Spreadsheet spr) {
|
|
||||||
//? true if valid
|
|
||||||
//? valid inputs are: A1, B14, C79, E99, F1, G99, J1, M98, ... (and all lower case variants)
|
|
||||||
|
|
||||||
positionToCheck = positionToCheck.toUpperCase();
|
|
||||||
|
|
||||||
//? Check if input is the right length
|
|
||||||
if (positionToCheck.length() < 2 || positionToCheck.length() > 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//? Check if input is in the right format
|
|
||||||
if (!(Character.isLetter(positionToCheck.charAt(0)) && Character.isDigit(positionToCheck.charAt(1)))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (positionToCheck.length() == 3) {
|
|
||||||
if (!(Character.isDigit(positionToCheck.charAt(2)))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the user inputted position is in the bounds of the spreadsheet.
|
|
||||||
* Case does not matter.
|
|
||||||
* @param positionToCheck The user inputted position as a string.
|
|
||||||
* @param spr The spreadsheet object. (This input is needed for tests)
|
|
||||||
* @return true if the position is in the bounds, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean userPositionBoundsErrorCheck(String positionToCheck, Spreadsheet spr) {
|
|
||||||
//? true if valid
|
|
||||||
|
|
||||||
positionToCheck = positionToCheck.toUpperCase();
|
|
||||||
|
|
||||||
if ((spr.getRow(positionToCheck) >= spr.getRowsLCount()) || (spr.getCol(positionToCheck) >= spr.getColsCount())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//? User input for a value or a formula
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prompts the user to input a value or a formula for the selected position.
|
|
||||||
* May be called multiple times, if the input is faulty.
|
|
||||||
* @param currentPos The position the user is currently inputting a value or a formula for.
|
|
||||||
* @return The user inputted value or formula as a string.
|
|
||||||
*/
|
|
||||||
public static String userValueFormulaInput(String currentPos) {
|
|
||||||
System.out.println();
|
|
||||||
System.out.printf("Input a value of a formula for the selected position: %s.%n", currentPos);
|
|
||||||
System.out.printf("Format for a value: 7 or 1337 %nFormat for a formula: =7*6 or =SUMME(A1:A3)%n");
|
|
||||||
System.out.print("Input: ");
|
|
||||||
String userCommandInput = keyboard.nextLine();
|
|
||||||
|
|
||||||
return userValueFormulaComputation(userCommandInput, currentPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* First method in the error check chain for the user input for a value or a formula.
|
|
||||||
* This method may call userValueFormulaInput() again, if the input is faulty.
|
|
||||||
* Checks if the input is empty and if not decides if the input is a value or a formula.
|
|
||||||
* Calls different methods to check for different errors.
|
|
||||||
* @param userValueFormulaInput The user inputted value or formula as a string.
|
|
||||||
* @param currentPos The position the user is currently inputting a value or a formula for.
|
|
||||||
* @return The user inputted value or formula as a string.
|
|
||||||
*/
|
|
||||||
public static String userValueFormulaComputation(String userValueFormulaInput, String currentPos) {
|
|
||||||
if (userValueFormulaInput.isEmpty()) {
|
|
||||||
System.out.println("Input is empty!");
|
|
||||||
return userValueFormulaInput(currentPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
//? Formula
|
|
||||||
if (userValueFormulaInput.charAt(0) == '=') {
|
|
||||||
if (!(userFormulaErrorCheck(userValueFormulaInput))) {
|
|
||||||
System.out.println("Invalid formula!");
|
|
||||||
return userValueFormulaInput(currentPos);
|
|
||||||
}
|
|
||||||
return userValueFormulaInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
//? Value
|
|
||||||
if (!(userValueErrorCheck(userValueFormulaInput))) {
|
|
||||||
System.out.println("Invalid value!");
|
|
||||||
return userValueFormulaInput(currentPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return userValueFormulaInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the user inputted formula is a function or expression.
|
|
||||||
* Removes the '=' at the beginning.
|
|
||||||
* To decide if a formula is a function, it simply checks if the formula starts with one of the function names.
|
|
||||||
* Calls different methods to check for different errors.
|
|
||||||
* Case does not matter.
|
|
||||||
* @param formulaToCheck The user inputted formula as a string.
|
|
||||||
* @return true if the formula is valid, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean userFormulaErrorCheck(String formulaToCheck) {
|
|
||||||
//? true if valid
|
|
||||||
//? valid inputs are: =7*6, =SUM(A1:A3), =A1, =A1+A2, =A1-A2, ... (and all lower case variants)
|
|
||||||
|
|
||||||
//? remove '=' at the beginning and make everything upper case
|
|
||||||
formulaToCheck = formulaToCheck.toUpperCase().substring(1);
|
|
||||||
|
|
||||||
if (formulaToCheck.startsWith("SUMME(") || formulaToCheck.startsWith("PRODUKT(") || formulaToCheck.startsWith("MITTELWERT(") || formulaToCheck.startsWith("STABW(") || formulaToCheck.startsWith("MIN(") || formulaToCheck.startsWith("MAX(")) {
|
|
||||||
return userFormulaFunctionErrorCheck(formulaToCheck);
|
|
||||||
}
|
|
||||||
|
|
||||||
return userFormulaExpressionErrorCheck(formulaToCheck);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks a function formula for errors.
|
|
||||||
* Checks if the formula is in the right format and if the cells in the formula are in the bounds of the spreadsheet.
|
|
||||||
* Checks for some special cases for different functions.
|
|
||||||
* @param functionToCheck The user inputted formula as a string.
|
|
||||||
* @return true if the formula is valid, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean userFormulaFunctionErrorCheck(String functionToCheck) {
|
|
||||||
String[] functionCorners = spr.isolateFunctionCorners(functionToCheck);
|
|
||||||
|
|
||||||
if (functionCorners.length != 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String functionCorner : functionCorners) {
|
|
||||||
if (!(spr.isValueCellName(functionCorner).equals("cellName"))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userPositionBoundsErrorCheck(functionCorner, spr)) {
|
|
||||||
System.out.print("Out of bounds - ");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (functionToCheck.startsWith("MITTELWERT(") || functionToCheck.startsWith("STABW(")) {
|
|
||||||
String[] functionBlock = spr.wholeFunctionBlock(functionToCheck);
|
|
||||||
boolean allEmpty = true;
|
|
||||||
|
|
||||||
for (String cell : functionBlock) {
|
|
||||||
if (!cell.isEmpty()) {
|
|
||||||
allEmpty = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allEmpty) {
|
|
||||||
System.out.print("Division by zero - ");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (functionToCheck.startsWith("STABW(")) {
|
|
||||||
String[] functionBlock = spr.wholeFunctionBlock(functionToCheck);
|
|
||||||
String[] notEmptyValues = spr.extractNotEmptyCells(functionBlock);
|
|
||||||
|
|
||||||
if (notEmptyValues.length < 2) {
|
|
||||||
System.out.print("Division by zero - ");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks an expression formula for errors.
|
|
||||||
* To be done in the future.
|
|
||||||
* @param expressionToCheck The user inputted expression formula as a string.
|
|
||||||
* @return true if the formula is valid, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean userFormulaExpressionErrorCheck(String expressionToCheck) {
|
|
||||||
//TODO ME
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the user inputted value is valid.
|
|
||||||
* Checks if the input is a positive or negative integer.
|
|
||||||
* @param valueToCheck The user inputted value as a string.
|
|
||||||
* @return true if the value is valid, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean userValueErrorCheck(String valueToCheck) {
|
|
||||||
//? true if valid
|
|
||||||
//? valid inputs are: 7, 1337, 0, , -213,...
|
|
||||||
|
|
||||||
//? For floating point numbers
|
|
||||||
// String digitCheckRegex = "-?\\d+(\\.\\d+)?";
|
|
||||||
//? For integers
|
|
||||||
String digitCheckRegex = "-?\\d+";
|
|
||||||
if (!(valueToCheck.matches(digitCheckRegex))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a program command.
|
|
||||||
* @param command The user inputted command as a string.
|
|
||||||
* @return Nothing.
|
|
||||||
* @throws FileNotFoundException If the file to load or save to is not found.
|
|
||||||
*/
|
|
||||||
public static void executeCommand(String command) throws FileNotFoundException {
|
|
||||||
switch (command) {
|
|
||||||
case "*clear":
|
|
||||||
progClear();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "*load":
|
|
||||||
progLoad();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "*save":
|
|
||||||
progSave();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "*exit":
|
|
||||||
progExit();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the program command to clear the table.
|
|
||||||
* @return Nothing.
|
|
||||||
*/
|
|
||||||
private static void progClear(){
|
|
||||||
System.out.println("Are you sure you want to clear the table? (yes/no)");
|
|
||||||
System.out.print("Input: ");
|
|
||||||
String userClearInput = keyboard.nextLine().toLowerCase();
|
|
||||||
|
|
||||||
if (userClearInput.equals("yes") || userClearInput.equals("y")){
|
|
||||||
spr.clearTable();
|
|
||||||
System.out.println("Table cleared!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the program command to load a table from a csv file.
|
|
||||||
* @return Nothing.
|
|
||||||
* @throws FileNotFoundException If the file to load is not found.
|
|
||||||
*/
|
|
||||||
private static void progLoad() throws FileNotFoundException {
|
|
||||||
spr.readCsv(saveFilePath, ",", "Amogus");
|
|
||||||
System.out.println("File loaded!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the program command to save the table to a csv file.
|
|
||||||
* @return Nothing.
|
|
||||||
* @throws FileNotFoundException If the file to save to is not found.
|
|
||||||
*/
|
|
||||||
private static void progSave() throws FileNotFoundException {
|
|
||||||
String savePath = saveFilePath;
|
|
||||||
spr.saveCsv(savePath);
|
|
||||||
System.out.println("File saved");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the program command to exit the program and asks the user to save the table.
|
|
||||||
* Case does not matter.
|
|
||||||
* @return Nothing.
|
|
||||||
* @throws FileNotFoundException If the file to save to is not found.
|
|
||||||
*/
|
|
||||||
private static void progExit() throws FileNotFoundException {
|
|
||||||
System.out.println("Do you want to save befor you exit? (yes/no)");
|
|
||||||
System.out.print("Input: ");
|
|
||||||
String userExitInput = keyboard.nextLine().toLowerCase();
|
|
||||||
|
|
||||||
if (userExitInput.equals("yes") || userExitInput.equals("y")) {
|
|
||||||
progSave();
|
|
||||||
}
|
|
||||||
System.out.println("Goodbye!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,57 +4,33 @@ package de.hs_mannheim.informatik.spreadsheet;
|
||||||
* Part of a simplified spreadsheet system for the PR1 programming lab at Hochschule Mannheim.
|
* Part of a simplified spreadsheet system for the PR1 programming lab at Hochschule Mannheim.
|
||||||
* A cell needs to be able to hold a formula and a value
|
* A cell needs to be able to hold a formula and a value
|
||||||
*
|
*
|
||||||
* @author Oliver Hummel & Victor Waitz
|
* @author Oliver Hummel
|
||||||
*/
|
*/
|
||||||
public class Cell {
|
public class Cell {
|
||||||
private String formula = "";
|
private String formula = "";
|
||||||
private String value = "";
|
private String value = "";
|
||||||
|
|
||||||
/**
|
|
||||||
* Public method to get the formula of the cell.
|
|
||||||
* @return formula of the cell.
|
|
||||||
*/
|
|
||||||
public String getFormula() {
|
public String getFormula() {
|
||||||
return formula;
|
return formula;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Public method to set the formula of the cell.
|
|
||||||
* @param formula formula of the cell.
|
|
||||||
*/
|
|
||||||
public void setFormula(String formula) {
|
public void setFormula(String formula) {
|
||||||
if (!formula.isEmpty())
|
if (!formula.isEmpty())
|
||||||
this.formula = formula.toUpperCase().substring(1); // removes '=' at the beginning
|
this.formula = formula.toUpperCase().substring(1); // removes '=' at the beginning
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Public method to get the value of the cell.
|
|
||||||
* @return value of the cell
|
|
||||||
*/
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Public method to set the value of the cell.
|
|
||||||
* @param value value of the cell.
|
|
||||||
*/
|
|
||||||
public void setValue(String value) {
|
public void setValue(String value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Public method to get cell value as a string.
|
|
||||||
* @return value as string.
|
|
||||||
*/
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("%4s", value);
|
return String.format("%4s", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Public method to check if the cell is empty.
|
|
||||||
* @return true if the cell is empty, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return value.isEmpty();
|
return value.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
package de.hs_mannheim.informatik.spreadsheet;
|
package de.hs_mannheim.informatik.spreadsheet;
|
||||||
|
|
||||||
import javax.naming.ldap.spi.LdapDnsProviderResult;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Scanner;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -14,7 +10,7 @@ import java.util.regex.Pattern;
|
||||||
* A simplified spreadsheet class for the PR1 programming lab at Hochschule Mannheim.
|
* A simplified spreadsheet class for the PR1 programming lab at Hochschule Mannheim.
|
||||||
* One aspect worth mentioning is that it only supports long numbers, not doubles.
|
* One aspect worth mentioning is that it only supports long numbers, not doubles.
|
||||||
*
|
*
|
||||||
* @author Oliver Hummel & Victor Waitz
|
* @author Oliver Hummel
|
||||||
*/
|
*/
|
||||||
public class Spreadsheet {
|
public class Spreadsheet {
|
||||||
Cell[][] cells;
|
Cell[][] cells;
|
||||||
|
@ -26,14 +22,7 @@ public class Spreadsheet {
|
||||||
*/
|
*/
|
||||||
public Spreadsheet(int rows, int cols) {
|
public Spreadsheet(int rows, int cols) {
|
||||||
|
|
||||||
if (rows > 99){
|
// TODO limit the maximum size on 99 (1..99) rows and 26 (A..Z) columns
|
||||||
System.out.printf("Row size %d is bigger then 99, value will be set to 99! %n", rows);
|
|
||||||
rows = 99;
|
|
||||||
}
|
|
||||||
if (cols > 26){
|
|
||||||
System.out.printf("Col size %d is bigger then 26, value will be set to 26! %n", cols);
|
|
||||||
cols = 26;
|
|
||||||
}
|
|
||||||
|
|
||||||
cells = new Cell[rows][cols];
|
cells = new Cell[rows][cols];
|
||||||
|
|
||||||
|
@ -45,75 +34,35 @@ public class Spreadsheet {
|
||||||
// -----
|
// -----
|
||||||
// retrieve or change values of cells
|
// retrieve or change values of cells
|
||||||
|
|
||||||
/**
|
|
||||||
* Private method to get a value from a cell in a spreadsheet.
|
|
||||||
* @param row The row of the cell.
|
|
||||||
* @param col The column of the cell.
|
|
||||||
* @return The value of the cell.
|
|
||||||
*/
|
|
||||||
private String get(int row, int col) {
|
private String get(int row, int col) {
|
||||||
return cells[row][col].getValue();
|
return cells[row][col].getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Public method to get a value from a cell in a spreadsheet.
|
|
||||||
* @param cellName The name of the cell.
|
|
||||||
* @return The value of the cell.
|
|
||||||
*/
|
|
||||||
public String get(String cellName) {
|
public String get(String cellName) {
|
||||||
cellName = cellName.toUpperCase();
|
cellName = cellName.toUpperCase();
|
||||||
return get(getRow(cellName), getCol(cellName));
|
return get(getRow(cellName), getCol(cellName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Private methode to put a value into a cell in a spreadsheet.
|
|
||||||
* @param row The row of the cell.
|
|
||||||
* @param col The column of the cell.
|
|
||||||
* @param value The value to put into the cell.
|
|
||||||
* @return Nothing.
|
|
||||||
*/
|
|
||||||
private void put(int row, int col, String value) {
|
private void put(int row, int col, String value) {
|
||||||
if (!value.startsWith("="))
|
if (!value.startsWith("="))
|
||||||
cells[row][col].setValue(value);
|
cells[row][col].setValue(value);
|
||||||
else {
|
else {
|
||||||
System.out.printf("Formula: %s %n", value);
|
|
||||||
cells[row][col].setFormula(value);
|
cells[row][col].setFormula(value);
|
||||||
evaluateCell(row, col);
|
evaluateCell(row, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Public method to put a value into a cell in a spreadsheet.
|
|
||||||
* Calls private methode put.
|
|
||||||
* @param cellName The name of the cell.
|
|
||||||
* @param value The value to put into the cell.
|
|
||||||
* @return Nothing.
|
|
||||||
*/
|
|
||||||
public void put(String cellName, String value) {
|
public void put(String cellName, String value) {
|
||||||
cellName = cellName.toUpperCase();
|
cellName = cellName.toUpperCase();
|
||||||
put(getRow(cellName), getCol(cellName), value);
|
put(getRow(cellName), getCol(cellName), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private int getCol(String cellName) {
|
||||||
* Method to get the column of a cell in a spreadsheet.
|
|
||||||
* @param cellName The name of the cell.
|
|
||||||
* @return The column of the cell.
|
|
||||||
*/
|
|
||||||
public int getCol(String cellName) {
|
|
||||||
return cellName.charAt(0) - 'A';
|
return cellName.charAt(0) - 'A';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private int getRow(String cellName) {
|
||||||
* Method to get the row of a cell in a spreadsheet.
|
return cellName.charAt(1) - '1';
|
||||||
* @param cellName The name of the cell.
|
|
||||||
* @return The row of the cell.
|
|
||||||
*/
|
|
||||||
public int getRow(String cellName) {
|
|
||||||
String row = "";
|
|
||||||
for (int i = 1; i < cellName.length(); i++){
|
|
||||||
row += cellName.charAt(i);
|
|
||||||
}
|
|
||||||
return Integer.parseInt(row) - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
|
@ -121,62 +70,24 @@ public class Spreadsheet {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A method for reading in data from a CSV file.
|
* A method for reading in data from a CSV file.
|
||||||
* @param filePath The file to read.
|
* @param path The file to read.
|
||||||
* @param separator The char used to split up the input, e.g. a comma or a semicolon.
|
* @param separator The char used to split up the input, e.g. a comma or a semicolon.
|
||||||
* @param startCellName The upper left cell where data from the CSV file should be inserted.
|
* @param starCellName The upper left cell where data from the CSV file should be inserted.
|
||||||
* @return Nothing.
|
* @return Nothing.
|
||||||
* @exception IOException If path does not exist.
|
* @exception IOException If path does not exist.
|
||||||
*/
|
*/
|
||||||
public void readCsv(String filePath, String separator, String startCellName) throws FileNotFoundException {
|
public void readCsv(String path, char separator, String startCellName) throws FileNotFoundException {
|
||||||
ArrayList<String> fileRows = new ArrayList<>();
|
// TODO: implement this
|
||||||
Scanner sc = new Scanner(new File(filePath));
|
|
||||||
|
|
||||||
while (sc.hasNextLine()) {
|
|
||||||
fileRows.add(sc.nextLine());
|
|
||||||
}
|
|
||||||
clearTable();
|
|
||||||
|
|
||||||
ArrayList <int[]> formulas = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int rowI = 0; rowI < fileRows.size(); rowI++) {
|
|
||||||
String row = fileRows.get(rowI);
|
|
||||||
String[] cells = row.split(separator);
|
|
||||||
|
|
||||||
for (int colI = 0; colI < cells.length; colI++) {
|
|
||||||
String cellContent = cells[colI].toUpperCase();
|
|
||||||
|
|
||||||
if (cellContent.startsWith("=")){
|
|
||||||
formulas.add(new int[]{rowI, colI});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
put(rowI, colI, cellContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int[] formulaPos : formulas){
|
|
||||||
int rowI = formulaPos[0];
|
|
||||||
int colI = formulaPos[1];
|
|
||||||
System.out.printf("Formula at %d-%d %n", rowI, colI);
|
|
||||||
|
|
||||||
String row = fileRows.get(rowI);
|
|
||||||
String formulaToFill = row.split(separator)[colI];
|
|
||||||
|
|
||||||
put(rowI, colI, formulaToFill);
|
|
||||||
}
|
|
||||||
|
|
||||||
sc.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A method for saving data to a CSV file.
|
* A method for saving data to a CSV file.
|
||||||
* @param filePath The file to write.
|
* @param path The file to write.
|
||||||
* @return Nothing.
|
* @return Nothing.
|
||||||
* @exception FileNotFoundException If path does not exist.
|
* @exception IOException If path does not exist.
|
||||||
*/
|
*/
|
||||||
public void saveCsv(String filePath) throws FileNotFoundException {
|
public void saveCsv(String path) throws FileNotFoundException {
|
||||||
PrintWriter out = new PrintWriter(filePath);
|
PrintWriter out = new PrintWriter(path);
|
||||||
|
|
||||||
for (Cell[] row : cells) {
|
for (Cell[] row : cells) {
|
||||||
for (Cell cell : row) {
|
for (Cell cell : row) {
|
||||||
|
@ -196,34 +107,25 @@ public class Spreadsheet {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method does the actual evaluation/calcluation of a specific cell
|
* This method does the actual evaluation/calcluation of a specific cell
|
||||||
* @param col the col of the cell to be evaluated
|
* @param cellName the name of the cell to be evaluated
|
||||||
* @param row the row of the cell to be evaluated
|
|
||||||
* @return Nothing.
|
* @return Nothing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private void evaluateCell(int row, int col) {
|
private void evaluateCell(int row, int col) {
|
||||||
String formula = cells[row][col].getFormula();
|
String formula = cells[row][col].getFormula();
|
||||||
System.out.printf("Formel in eval: %s %n", formula);
|
|
||||||
String result = "";
|
String result = "";
|
||||||
|
|
||||||
if (formula.startsWith("SUMME(")) // e.g. SUMME(A3:A8)
|
if (formula.startsWith("SUMME(")) // e.g. SUMME(A3:A8)
|
||||||
result = "" + sum(formula);
|
result = "" + sum(formula.substring(6, 8), formula.substring(9, 11)); // TODO adapt to cells with two digits
|
||||||
|
|
||||||
else if (formula.startsWith("PRODUKT(")) // e.g. PRODUKT(A3:B9)
|
else if (formula.startsWith("PRODUKT(")) // e.g. PRODUKT(A3:B9)
|
||||||
result = "" + prod(formula);
|
result = "TODO"; // TODO
|
||||||
|
|
||||||
else if (formula.startsWith("MITTELWERT(")) // e.g. MITTELWERT(A3:A5)
|
else if (formula.startsWith("MITTELWERT(")) // e.g. MITTELWERT(A3:A5)
|
||||||
result = "" + avrg(formula);
|
result = "TODO"; // TODO
|
||||||
|
|
||||||
else if (formula.startsWith("STABW(")) // e.g. STABW(C6:D8) -> Standardabweichung
|
else if (formula.startsWith("STABW(")) // e.g. STABW(C6:D8) -> Standardabweichung
|
||||||
result = "" + stdDevp(formula);
|
result = "TODO"; // TODO
|
||||||
|
|
||||||
else if (formula.startsWith("MIN(")) // e.g. MIN(C13:H13) -> größter Wert
|
else if (formula.startsWith("MIN(")) // e.g. MIN(C13:H13) -> größter Wert
|
||||||
result = "" + min(formula);
|
result = "TODO"; // TODO
|
||||||
|
|
||||||
else if (formula.startsWith("MAX(")) // e.g. MAX(A1:A10) -> Standardabweichung
|
else if (formula.startsWith("MAX(")) // e.g. MAX(A1:A10) -> Standardabweichung
|
||||||
result = "" + max(formula);
|
result = "TODO"; // TODO
|
||||||
|
|
||||||
else if (!formula.isEmpty()) {
|
else if (!formula.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
result = "" + calculate(formula);
|
result = "" + calculate(formula);
|
||||||
|
@ -231,239 +133,23 @@ public class Spreadsheet {
|
||||||
result = "exc.";
|
result = "exc.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cells[row][col].setValue("" + result);
|
cells[row][col].setValue("" + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to extract the corner cells for a function formula.
|
|
||||||
* @param formula The formula to isolate the corners for
|
|
||||||
* @return The formulas corners.
|
|
||||||
*/
|
|
||||||
public String[] isolateFunctionCorners(String formula){
|
|
||||||
//? isolate corners
|
|
||||||
ArrayList<String> corners = new ArrayList<String>();
|
|
||||||
|
|
||||||
Matcher m = Pattern.compile("[A-Z]\\d+").matcher(formula);
|
|
||||||
while(m.find()) {
|
|
||||||
String s = m.group();
|
|
||||||
|
|
||||||
if (!s.isEmpty()){
|
|
||||||
corners.add(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return corners.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A methode to extract a block of cells used in a function formula,
|
|
||||||
* such as A1 and B3 for SUMME(A1:B3).
|
|
||||||
* Calls the isolateFunctionCorners methode to get the blocks corners.
|
|
||||||
* @param formula The formula to get the block for.
|
|
||||||
* @return The cell block.
|
|
||||||
*/
|
|
||||||
public String[] wholeFunctionBlock(String formula){
|
|
||||||
String[] corners = isolateFunctionCorners(formula);
|
|
||||||
|
|
||||||
String cornerOne = corners[0];
|
|
||||||
char colOne = cornerOne.charAt(0);
|
|
||||||
int rowOne = Integer.parseInt(cornerOne.substring(1));
|
|
||||||
|
|
||||||
String cornerTwo = corners[1];
|
|
||||||
char colTwo = cornerTwo.charAt(0);
|
|
||||||
int rowTwo = Integer.parseInt(cornerTwo.substring(1));
|
|
||||||
|
|
||||||
ArrayList<String> block = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int rowInt = rowOne; rowInt <= rowTwo; rowInt++) {
|
|
||||||
for (char charCol = colOne; charCol <= colTwo; charCol++) {
|
|
||||||
block.add(String.format("%c%d", charCol, rowInt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return block.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method for calculating the sum of a rectangular block of cells, such as from A1 to B3.
|
* Method for calculating the sum of a rectangular block of cells, such as from A1 to B3.
|
||||||
* @param formula The formula to calculate the sum.
|
* @param startCellName The name of the cell in the upper left corner of the rectangle.
|
||||||
|
* @param endCellName The name of the cell in the lower right corner of the rectangle.
|
||||||
* @return The sum calculated.
|
* @return The sum calculated.
|
||||||
*/
|
*/
|
||||||
public long sum(String formula) {
|
private long sum(String startCellName, String endCellName) {
|
||||||
String[] block = wholeFunctionBlock(formula);
|
// TODO implement
|
||||||
long res = 0;
|
|
||||||
|
|
||||||
for (String cellName : block){
|
return 0;
|
||||||
String cellValue = get(cellName);
|
|
||||||
long value = cellValue.isEmpty() ? 0 : Long.parseLong(cellValue);
|
|
||||||
res += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method for calculating the product of a rectangular block of cells, such as from A1 to B3.
|
|
||||||
* @param formula The formula to calculate the product.
|
|
||||||
* @return The product calculated.
|
|
||||||
*/
|
|
||||||
public long prod(String formula){
|
|
||||||
String[] block = wholeFunctionBlock(formula);
|
|
||||||
|
|
||||||
long res = 1;
|
|
||||||
boolean allEmpty = true;
|
|
||||||
|
|
||||||
for (String cellName : block){
|
|
||||||
String cellValue = get(cellName);
|
|
||||||
if (!cellValue.isEmpty()){
|
|
||||||
allEmpty = false;
|
|
||||||
}
|
|
||||||
long value = cellValue.isEmpty() ? 1 : Long.parseLong(cellValue);
|
|
||||||
res *= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allEmpty){
|
|
||||||
res = 0;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method for calculating the average of a rectangular block of cells, such as from A1 to B3.
|
|
||||||
* @param formula The formula to calculate the average.
|
|
||||||
* @return The average calculated.
|
|
||||||
*/
|
|
||||||
public long avrg(String formula){
|
|
||||||
String[] block = wholeFunctionBlock(formula);
|
|
||||||
|
|
||||||
boolean allEmpty = true;
|
|
||||||
long res = 0;
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
for (String cellName : block){
|
|
||||||
String cellValue = get(cellName);
|
|
||||||
if (cellValue.isEmpty()){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
allEmpty = false;
|
|
||||||
|
|
||||||
res += Long.parseLong(cellValue);
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
if (allEmpty){
|
|
||||||
System.out.println("Division by zero! Value set to 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = res/counter;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method for calculating the standard deviation of a rectangular block of cells, such as from A1 to B3.
|
|
||||||
* Calls the average method.
|
|
||||||
* @param formula The formula to calculate the standard deviation.
|
|
||||||
* @return The standard deviation calculated.
|
|
||||||
*/
|
|
||||||
public long stdDevp(String formula){
|
|
||||||
String[] block = wholeFunctionBlock(formula);
|
|
||||||
|
|
||||||
String[] notEmptyValues = extractNotEmptyCells(block);
|
|
||||||
|
|
||||||
if(notEmptyValues.length < 2){
|
|
||||||
System.out.println("Division by zero! Value set to 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long meanValue = avrg(formula);
|
|
||||||
long squaredDiffsSum = 0;
|
|
||||||
|
|
||||||
for (String value : notEmptyValues){
|
|
||||||
long difference = Long.parseLong(value) - meanValue;
|
|
||||||
squaredDiffsSum += (long) Math.pow(difference, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
long variance = squaredDiffsSum / (notEmptyValues.length - 1);
|
|
||||||
return (long) Math.sqrt(variance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method for selecting the minimum of a rectangular block of cells, such as from A1 to B3.
|
|
||||||
* @param formula The formula to select the minimum from.
|
|
||||||
* @return The minimum selected.
|
|
||||||
*/
|
|
||||||
public long min(String formula){
|
|
||||||
String[] block = wholeFunctionBlock(formula);
|
|
||||||
|
|
||||||
String firstElement = "";
|
|
||||||
long currentSmallest = 0;
|
|
||||||
for (int i = 0; i < block.length; i++) {
|
|
||||||
String cellValue = get(block[i]);
|
|
||||||
if (cellValue.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (firstElement.isEmpty()){
|
|
||||||
firstElement = get(block[i]);
|
|
||||||
currentSmallest = Long.parseLong(firstElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
long value = Long.parseLong(cellValue);
|
|
||||||
if (value < currentSmallest){
|
|
||||||
currentSmallest = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currentSmallest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method for selecting the maximum of a rectangular block of cells, such as from A1 to B3.
|
|
||||||
* @param formula The formula to select the maximum from.
|
|
||||||
* @return The maximum selected.
|
|
||||||
*/
|
|
||||||
public long max(String formula){
|
|
||||||
String[] block = wholeFunctionBlock(formula);
|
|
||||||
|
|
||||||
String firstElement = "";
|
|
||||||
long currentBiggest = 0;
|
|
||||||
for (int i = 0; i < block.length; i++) {
|
|
||||||
String cellValue = get(block[i]);
|
|
||||||
if (cellValue.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstElement.isEmpty()){
|
|
||||||
firstElement = get(block[i]);
|
|
||||||
currentBiggest = Long.parseLong(firstElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
long value = Long.parseLong(cellValue);
|
|
||||||
if (value > currentBiggest){
|
|
||||||
currentBiggest = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currentBiggest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to extract only cells which are not empty from a previously calculated block from a
|
|
||||||
* function formula.
|
|
||||||
* @param block Block with empty and not empty cells.
|
|
||||||
* @return Block with only not empty cells.
|
|
||||||
*/
|
|
||||||
public String[] extractNotEmptyCells(String[] block){
|
|
||||||
ArrayList<String> notEmptyValues = new ArrayList<String>();
|
|
||||||
|
|
||||||
for (String cell : block) {
|
|
||||||
String cellValue = get(cell);
|
|
||||||
|
|
||||||
if (!cellValue.isEmpty()){
|
|
||||||
notEmptyValues.add(cellValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return notEmptyValues.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* This method calculates the result of a "normal" algebraic expression. It only needs to support
|
* This method calculates the result of a "normal" algebraic expression. It only needs to support
|
||||||
* expressions like =B4 or =2+A3-B2, i.e. only with int numbers and other cells and with plus,
|
* expressions like =B4 or =2+A3-B2, i.e. only with int numbers and other cells and with plus,
|
||||||
* minus, times, split only. An expression always starts with either a number or a cell name. If it
|
* minus, times, split only. An expression always starts with either a number or a cell name. If it
|
||||||
|
@ -472,176 +158,26 @@ public class Spreadsheet {
|
||||||
* @param formula The expression to be evaluated.
|
* @param formula The expression to be evaluated.
|
||||||
* @return The result calculated.
|
* @return The result calculated.
|
||||||
*/
|
*/
|
||||||
public long calculate(String formula) throws ArithmeticException {
|
private long calculate(String formula) throws ArithmeticException {
|
||||||
long res = 0;
|
|
||||||
|
|
||||||
ArrayList<String> formulaElements = extractExpressionElements(formula);
|
|
||||||
|
|
||||||
String firstElement = formulaElements.get(0);
|
|
||||||
|
|
||||||
if (isValueCellName(firstElement).equals("cellName")){
|
|
||||||
String cellValue = get(firstElement);
|
|
||||||
res = cellValue.isEmpty() ? 0 : Long.parseLong(cellValue);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res = Long.parseLong(firstElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < formulaElements.size(); i = i+2) {
|
|
||||||
res = singleCalculation(res, formulaElements.get(i+1), formulaElements.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to extract every single element of an expression and stores them as a separate element in the
|
|
||||||
* String ArrayList formulaElements and returns it.
|
|
||||||
* An expression element is either a number, a cell name or an operator.
|
|
||||||
* @param formula The formula expression to extract elements from.
|
|
||||||
* @return The elements as single elements.
|
|
||||||
*/
|
|
||||||
public static ArrayList<String> extractExpressionElements(String formula){
|
|
||||||
Matcher m = Pattern.compile("([A-Z][0-9]*)|[-\\+\\*/]|[0-9]*").matcher(formula);
|
Matcher m = Pattern.compile("([A-Z][0-9]*)|[-\\+\\*/]|[0-9]*").matcher(formula);
|
||||||
|
|
||||||
ArrayList<String> formulaElements = new ArrayList<String>();
|
long res = 0;
|
||||||
|
|
||||||
while (m.find()) {
|
// TODO implement
|
||||||
|
|
||||||
|
// uncomment the following to see an example how the elements of a formula can be accessed
|
||||||
|
while (m.find()) { // m.find() must always be used before m.group()
|
||||||
String s = m.group();
|
String s = m.group();
|
||||||
if (!s.isEmpty()) {
|
if (!s.isEmpty()) {
|
||||||
formulaElements.add(s);
|
System.out.println(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return formulaElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to calculate a single calculation. A single calculation always uses one operator and one value part.
|
|
||||||
* The value part can be a cell name or a value. The calculation takes the given previous solution and uses the given
|
|
||||||
* operator and the given value part to calculate and return a new solution.
|
|
||||||
* @param res The previous result of a calculation.
|
|
||||||
* @param element The element to calculate to the previous result.
|
|
||||||
* @param operator The operator used to calculate previous result and element.
|
|
||||||
* @return The new result.
|
|
||||||
*/
|
|
||||||
private long singleCalculation(long res, String element, String operator){
|
|
||||||
String elementType = isValueCellName(element);
|
|
||||||
|
|
||||||
if (elementType.equals("cellName")){
|
|
||||||
element = get(element);
|
|
||||||
}
|
|
||||||
long value = element.isEmpty() ? 0 : Long.parseLong(element);
|
|
||||||
|
|
||||||
|
|
||||||
switch (operator) {
|
|
||||||
case "+":
|
|
||||||
res += value;
|
|
||||||
break;
|
|
||||||
case "-":
|
|
||||||
res -= value;
|
|
||||||
break;
|
|
||||||
case "*":
|
|
||||||
res *= value;
|
|
||||||
break;
|
|
||||||
case "/":
|
|
||||||
if (value == 0){
|
|
||||||
throw new ArithmeticException("Division by zero");
|
|
||||||
}
|
|
||||||
res /= value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode to determine if a value part is either a cell name or a value.
|
|
||||||
* Has the possibility to determine floating point numbers for the future.
|
|
||||||
* @param sToCheck The string to decide.
|
|
||||||
* @return The String containing the information if it is a cell name or a value.
|
|
||||||
*/
|
|
||||||
public String isValueCellName(String sToCheck){
|
|
||||||
//? 7 -> "value", A1 -> "cellName", 7A -> "invalid"
|
|
||||||
|
|
||||||
//? For floating point numbers
|
|
||||||
// String digitCheckRegex = "-?\\d+(\\.\\d+)?";
|
|
||||||
//? For integers
|
|
||||||
String digitCheckRegex = "-?\\d+";
|
|
||||||
if (sToCheck.matches(digitCheckRegex)){
|
|
||||||
return "value";
|
|
||||||
}
|
|
||||||
|
|
||||||
//? For cell names
|
|
||||||
String cellNameCheckRegex = "[A-Z][0-9]*";
|
|
||||||
if (sToCheck.matches(cellNameCheckRegex)){
|
|
||||||
return "cellName";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "invalid";
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of rows in the spreadsheet.
|
|
||||||
* @return amount rows.
|
|
||||||
*/
|
|
||||||
public int getRowsLCount() {
|
|
||||||
return cells.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of columns in the spreadsheet.
|
|
||||||
* @return amount columns.
|
|
||||||
*/
|
|
||||||
public int getColsCount() {
|
|
||||||
return cells[0].length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the spreadsheet, it fills every value and formula to zero.
|
|
||||||
* @return Nothing.
|
|
||||||
*/
|
|
||||||
public void clearTable() {
|
|
||||||
int rows = getRowsLCount();
|
|
||||||
int cols = getColsCount();
|
|
||||||
|
|
||||||
for (int r = 0; r < rows; r++) {
|
|
||||||
for (int c = 0; c < cols; c++) {
|
|
||||||
cells[r][c].setValue("");
|
|
||||||
cells[r][c].setFormula("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a special table for testing purposes.
|
|
||||||
* @return Nothing.
|
|
||||||
*/
|
|
||||||
public void loadSpecialTable(){
|
|
||||||
clearTable();
|
|
||||||
|
|
||||||
put("A1", "1");
|
|
||||||
put("A2", "2");
|
|
||||||
put("A3", "3");
|
|
||||||
put("A4", "4");
|
|
||||||
put("B1", "5");
|
|
||||||
put("B2", "6");
|
|
||||||
put("B3", "7");
|
|
||||||
put("B4", "8");
|
|
||||||
put("K1", "200");
|
|
||||||
put("K11", "100");
|
|
||||||
put("J4", "4");
|
|
||||||
put("I10", "69");
|
|
||||||
put("F5", "3");
|
|
||||||
put("G4", "2");
|
|
||||||
put("G5", "3");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of the spreadsheet.
|
|
||||||
* @return The spreadsheet as a string.
|
|
||||||
*/
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
@ -662,4 +198,5 @@ public class Spreadsheet {
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,243 +0,0 @@
|
||||||
package de.hs_mannheim.informatik.spreadsheet;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
|
|
||||||
class AxelTest {
|
|
||||||
|
|
||||||
// --------- Class Vars ---------
|
|
||||||
Spreadsheet testspr = new Spreadsheet(11,11);
|
|
||||||
|
|
||||||
|
|
||||||
// --------- Input tests ---------
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Command input error check")
|
|
||||||
void userCommandErrorCheck() {
|
|
||||||
String[] successTestList = {"*exit", "*save", "*load", "*help", "*eXiT", "*SAVE", "*LoAd", "*hElP"};
|
|
||||||
String[] failureTestList = {"exit", "save", "load", "help", "eXiT", "SAVE", "LoAd", "hElP", "*exit*", "*save*", "*load*", "*help*", "*eXiT*", "*SAVE*", "*LoAd*", "*hElP*", "*test", "*TEST", "*saev", "*xeit"};
|
|
||||||
|
|
||||||
for (String successTest : successTestList) {
|
|
||||||
assertTrue(Axel.userCommandErrorCheck(successTest));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String failureTest : failureTestList) {
|
|
||||||
assertFalse(Axel.userCommandErrorCheck(failureTest));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Position input error check")
|
|
||||||
void userPositionErrorCheck() {
|
|
||||||
//? Overall format test
|
|
||||||
String[] successTestList = {"A1", "B14", "C79", "E99", "F1", "G99", "J1", "M98", "N67", "o45", "p23", "q12", "r2"};
|
|
||||||
String[] failureTestList = {"A100", "Z101", "AA1", "AB2", "ZZ1", "A1A", "FHT", "AAA", "G3U", "ZZZ", "2A", "47H", "AAAA", "test", "TEST", "save", "*save", "*exit"};
|
|
||||||
|
|
||||||
for (String successTest : successTestList) {
|
|
||||||
assertTrue(Axel.userPositionErrorCheck(successTest, testspr));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String failureTest : failureTestList) {
|
|
||||||
assertFalse(Axel.userPositionErrorCheck(failureTest, testspr));
|
|
||||||
}
|
|
||||||
|
|
||||||
//? Out of bounds test
|
|
||||||
Spreadsheet smallTestSpr = new Spreadsheet(6,8);
|
|
||||||
String[] successBoundsTest = {"A1", "a1", "b3", "c5", "A3", "H6", "h6"};
|
|
||||||
String[] failureBoundsTest = {"i2", "J6", "B7", "K9", "Z99"};
|
|
||||||
|
|
||||||
for (String successTest : successBoundsTest) {
|
|
||||||
assertTrue(Axel.userPositionBoundsErrorCheck(successTest, smallTestSpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String failureTest : failureBoundsTest) {
|
|
||||||
assertFalse(Axel.userPositionBoundsErrorCheck(failureTest, smallTestSpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Value input error check")
|
|
||||||
void userValueErrorCheck() {
|
|
||||||
String[] successTestList = {"0", "1", "-1", "1234", "4324", "-465"};
|
|
||||||
String[] failureTestList = {"a", "aa", "A!", "A1", "wef", "-a", "a-","-1a"};
|
|
||||||
|
|
||||||
for (String successTest : successTestList) {
|
|
||||||
assertTrue(Axel.userValueErrorCheck(successTest));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String failureTest : failureTestList) {
|
|
||||||
assertFalse(Axel.userValueErrorCheck(failureTest));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Formula input error check")
|
|
||||||
void userFormulaErrorCheck() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------- Calculation tests ---------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Normal calculation")
|
|
||||||
void calculate() {
|
|
||||||
putTestSpr();
|
|
||||||
|
|
||||||
String[] successTestList = {"=2*3", "=2+3", "=5-2", "=6/2", "7/2", "101/2", "=5+6-10*2", "=4-3+50-1/2", "=A1", "=K11", "=A1+A2+A3+A4", "=K11/2/5*2-15", "=a1+A2*a4-6+E7", "=a2-A1+J4-3"};
|
|
||||||
long[] successTestResult = {6, 5, 3, 3, 3, 50, 2, 25, 1, 100, 10, 5, 6, 2};
|
|
||||||
|
|
||||||
String[] failureTestList = {"5+1", "7-4", "6*2", "15/5", "5+4", "10-7", "5*3", "9/3", "=A1", "=K11", "=A1+A3", "=K11-10/2+B1"};
|
|
||||||
long[] failureTestResult = {5, 7, 10, 4, 8, 4, 16, 2, 2, 200, 3, 40};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++) {
|
|
||||||
// Uppercasing the formula happens in the code too, just in a different place which is not tested
|
|
||||||
String formula = successTestList[i].toUpperCase();
|
|
||||||
assertEquals(successTestResult[i], testspr.calculate(formula));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < failureTestList.length; i++) {
|
|
||||||
String formula = failureTestList[i].toUpperCase();
|
|
||||||
assertNotEquals(failureTestResult[i], testspr.calculate(failureTestList[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Is CellName")
|
|
||||||
void isValueCellName(){
|
|
||||||
String[] successValueTestList = {"7", "0", "1", "420", "424", "23212"};
|
|
||||||
String[] successCellNameTestList = {"A1", "K11", "B6", "g5", "k11"};
|
|
||||||
|
|
||||||
for (String successValue : successValueTestList){
|
|
||||||
successValue = successValue.toUpperCase();
|
|
||||||
assertEquals("value", testspr.isValueCellName(successValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String successCellName : successCellNameTestList){
|
|
||||||
successCellName = successCellName.toUpperCase();
|
|
||||||
assertEquals("cellName", testspr.isValueCellName(successCellName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Isolate Corner")
|
|
||||||
void isolateFunctionCorners(){
|
|
||||||
String[] successTestList = {"SUMME(A1:B3)", "SUMME(a3:k5)", "PRODUKT(C3:G6)", "PRODUKT(c2:g5)", "MITTELWERT(A2:j9)", "mittelwert(b4:H8)", "STABW(c7:g7)", "MIN(a1:A6)", "max(f4:h7)", "MAX(E2:j7)"};
|
|
||||||
String[][] successResultList = {{"A1", "B3"}, {"A3", "K5"}, {"C3", "G6"}, {"C2", "G5"}, {"A2", "J9"}, {"B4", "H8"}, {"C7", "G7"}, {"A1", "A6"}, {"F4", "H7"}, {"E2", "J7"}};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++){
|
|
||||||
String formula = successTestList[i].toUpperCase();
|
|
||||||
assertArrayEquals(successResultList[i], testspr.isolateFunctionCorners(formula));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Extract whole block")
|
|
||||||
void wholeFunctionBlock(){
|
|
||||||
String[] successTestList = {"SUMME(A1:C4)", "summe(F4:H7)", "Max(D4:D7)", "min(a1:d1)"};
|
|
||||||
String[][] successResultList = {{"A1", "B1", "C1", "A2", "B2", "C2", "A3", "B3", "C3", "A4", "B4", "C4"}, {"F4", "G4", "H4", "F5", "G5", "H5", "F6", "G6", "H6", "F7", "G7", "H7"}, {"D4", "D5", "D6", "D7"}, {"A1", "B1", "C1", "D1"}};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++){
|
|
||||||
String testElement = successTestList[i].toUpperCase();
|
|
||||||
assertArrayEquals(successResultList[i], testspr.wholeFunctionBlock(testElement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Sum")
|
|
||||||
void sum(){
|
|
||||||
putTestSpr();
|
|
||||||
String[] successTestList = {"SUMME(A1:B2)", "summe(B1:e1)", "Summe(B4:I10)", "SUMME(K1:K11)", "SUMME(F1:H1)", "SUMME(F4:G5)", "SUMME(A3:a3)"};
|
|
||||||
long[] successResultList = {14, 5, 85, 300, 0, 8, 3};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++) {
|
|
||||||
String testElement = successTestList[i].toUpperCase();
|
|
||||||
assertEquals(successResultList[i], testspr.sum(testElement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Product")
|
|
||||||
void prod(){
|
|
||||||
putTestSpr();
|
|
||||||
String[] successTestList = {"PRODUKT(A1:B2)", "PRODUKT(A2:B3)", "PRODUKT(B1:C4)", "Produkt(F1:H1)", "produkt(f4:g5)", "PRODUKT(A3:a3)"};
|
|
||||||
long[] successResultList = {60, 252, 1680, 0, 18, 3};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++) {
|
|
||||||
String testElement = successTestList[i].toUpperCase();
|
|
||||||
assertEquals(successResultList[i], testspr.prod(testElement));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Average")
|
|
||||||
void avrg(){
|
|
||||||
putTestSpr();
|
|
||||||
String[] successTestList = {"MITTELWERT(A1:B4)", "MITTELWERT(A3:B4)", "MITTELWERT(A1:A4)", "mittelwert(K1:K11)","Mittelwert(F1:H1)" ,"MITTELWERT(f4:g5)", "MITTELWERT(A3:a3)"};
|
|
||||||
long[] successResultList = {4, 5, 2, 150, 0, 2, 3};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++) {
|
|
||||||
String testElement = successTestList[i].toUpperCase();
|
|
||||||
assertEquals(successResultList[i], testspr.avrg(testElement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Standard deviation")
|
|
||||||
void stdDevp(){
|
|
||||||
putTestSpr();
|
|
||||||
String[] successTestList = {"STABW(A1:B4)", "STABW(A2:B3)", "STABW(A1:A4)", "STABW(K1:K11)", "stabw(f1:H1)", "Stabw(f4:g5)", "STAbW(a3:a3)"};
|
|
||||||
long[] successResultList = {2, 2, 1, 70, 0, 1, 0};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++) {
|
|
||||||
String testElement = successTestList[i].toUpperCase();
|
|
||||||
assertEquals(successResultList[i], testspr.stdDevp(testElement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Min value")
|
|
||||||
void min(){
|
|
||||||
putTestSpr();
|
|
||||||
String[] successTestList = {"MIN(A1:B4)", "MIN(A2:B3)", "MIN(A1:A4)", "MIN(K1:K11)", "min(f1:H1)", "Min(f4:g5)", "min(a3:a3)"};
|
|
||||||
long[] successResultList = {1, 2, 1, 100, 0, 2, 3};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++) {
|
|
||||||
String testElement = successTestList[i].toUpperCase();
|
|
||||||
assertEquals(successResultList[i], testspr.min(testElement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.jupiter.api.Test
|
|
||||||
@org.junit.jupiter.api.DisplayName("Max value")
|
|
||||||
void max(){
|
|
||||||
putTestSpr();
|
|
||||||
String[] successTestList = {"MAX(A1:B4)", "MAX(A2:B3)", "MAX(A1:A4)", "MAX(K1:K11)", "max(f1:H1)", "Max(f4:g5)", "max(a3:a3)"};
|
|
||||||
long[] successResultList = {8, 7, 4, 200, 0, 3, 3};
|
|
||||||
|
|
||||||
for (int i = 0; i < successTestList.length; i++) {
|
|
||||||
String testElement = successTestList[i].toUpperCase();
|
|
||||||
assertEquals(successResultList[i], testspr.max(testElement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putTestSpr(){
|
|
||||||
testspr.put("A1", "1");
|
|
||||||
testspr.put("A2", "2");
|
|
||||||
testspr.put("A3", "3");
|
|
||||||
testspr.put("A4", "4");
|
|
||||||
testspr.put("B1", "5");
|
|
||||||
testspr.put("B2", "6");
|
|
||||||
testspr.put("B3", "7");
|
|
||||||
testspr.put("B4", "8");
|
|
||||||
testspr.put("K1", "200");
|
|
||||||
testspr.put("K11", "100");
|
|
||||||
testspr.put("J4", "4");
|
|
||||||
testspr.put("I10", "69");
|
|
||||||
testspr.put("F5", "3");
|
|
||||||
testspr.put("G4", "2");
|
|
||||||
testspr.put("G5", "3");
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue