1
0
Fork 0
PR1-Spreadsheet/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java

425 lines
11 KiB
Java

package de.hs_mannheim.informatik.spreadsheet;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
/**
* 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.
*p
* @author Oliver Hummel
*/
public class Spreadsheet {
Cell[][] cells;
/**
* Constructor that creates a Spreadsheet of size rows * cols.
* @param rows number of rows
* @param cols number of columns
*/
public Spreadsheet(int rows, int cols) {
// TODO limit the maximum size on 99 (1..99) rows and 26 (A..Z) columns
if (rows > 99) {
rows = 99;
} else if (rows <= 0) {
rows = 1;
}
if (cols > 26) {
cols = 26;
} else if (cols <= 0) {
cols = 1;
}
cells = new Cell[rows][cols];
for (int r = 0; r < rows; r++)
for (int c = 0; c < cols; c++)
cells[r][c] = new Cell();
}
// -----
// retrieve or change values of cells
private String get(int row, int col) {
return cells[row][col].getValue();
}
public String get(String cellName) {
cellName = cellName.toUpperCase();
return get(getRow(cellName), getCol(cellName));
}
private void put(int row, int col, String value) {
if (!value.startsWith("="))
cells[row][col].setValue(value);
else {
cells[row][col].setFormula(value);
evaluateCell(row, col);
}
}
public void put(String cellName, String value) {
cellName = cellName.toUpperCase();
put(getRow(cellName), getCol(cellName), value);
}
private int getCol(String cellName) {
int merker = 0;
for (int i = 0; i < cellName.length(); i++) {
if (cellName.charAt(i) >= 'A' && cellName.charAt(i) <= 'Z') {
merker = (merker * 10) + (cellName.charAt(i) - ('A'-1));
} else {
break;
}
}
return merker-1;
}
private int getRow(String cellName) {
int merker = 0;
for (int i = 0; i < cellName.length(); i++) {
if (!(cellName.charAt(i) >= 'A' && cellName.charAt(i) <= 'Z')) {
merker = (merker * 10) + (cellName.charAt(i) - '0');
}
}
return merker-1;
}
public boolean zelleneingabe_pruefen(String a) {
if (a.length() < 2) { //es soll eine einzelne Zelle angesprochen werde, also muss dafür die länge >2 sein
return false;
}
if (getRow(a) < 0 || getRow(a) >= cells.length) { //überprüfung ob die eingabe in die rows länge passt
return false;
}
if (getCol(a) < 0 || getCol(a) >= cells[0].length) { //überprüfung ob die eingabe in die Columns länge passt
return false;
}
return true;
}
// -----
// business logic
/**
* A method for reading in data from a CSV file.
* @param path The file to read.
* @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.
* @return Nothing.
* @exception IOException If path does not exist.
*/
public void readCsv(String path, char separator, String startCellName) throws FileNotFoundException {
// TODO: implement this
ArrayList<String> lines = readFile(path);
String[] einzelnde_lines = new String[lines.size()];
int row_startcell = getRow(startCellName);
int col_startcell = getCol(startCellName);
String[][] zwischenspeicher = new String[cells.length - row_startcell][cells[0].length - col_startcell];
for (int i = 0; i < einzelnde_lines.length; i++) {
zwischenspeicher[i] = lines.get(i).split(separator+""); // +"" um aus dem Char ein String zu machen
for (int j = 0; j < zwischenspeicher[i].length; j++) {
put(row_startcell+i,col_startcell+j,zwischenspeicher[i][j]);
}
}
}
public static ArrayList<String> readFile(String path) throws FileNotFoundException {
ArrayList<String> lines = new ArrayList<>();
Scanner sc = new Scanner(new File(path));
while (sc.hasNextLine()) {
lines.add(sc.nextLine());
}
sc.close();
return lines;
}
/**
* A method for saving data to a CSV file.
* @param path The file to write.
* @return Nothing.
* @exception IOException If path does not exist.
*/
public void saveCsv(String path) throws FileNotFoundException {
PrintWriter out = new PrintWriter(path);
for (Cell[] row : cells) {
for (Cell cell : row) {
if (!cell.getFormula().isEmpty())
out.print("=" + cell.getFormula());
else
out.print(cell.getValue());
if (cell != row[cells[0].length-1]) // "[0]" -> nimmt sonst die falsche Länge!
out.print(",");
}
out.println();
}
out.close();
}
/**
* This method does the actual evaluation/calcluation of a specific cell
* @param cellName the name of the cell to be evaluated
* @return Nothing.
*/
private void evaluateCell(int row, int col) {
String formula = cells[row][col].getFormula();
String result = "";
if (formula.startsWith("SUMME(")) // e.g. SUMME(A3:A8)
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)
result = "" + pro(formula.substring(8, 10), formula.substring(11, 13));
else if (formula.startsWith("MITTELWERT(")) // e.g. MITTELWERT(A3:A5)
result = "" + mittelwert(formula.substring(11, 13), formula.substring(14, 16));
else if (formula.startsWith("STABW(")) // e.g. STABW(C6:D8) -> Standardabweichung
result = "TODO"; // TODO
else if (formula.startsWith("MIN(")) // e.g. MIN(C13:H13) -> kleinster Wert
result = "" + min(formula.substring(4, 6), formula.substring(7, 9));
else if (formula.startsWith("MAX(")) // e.g. MAX(A1:A10) -> größter Wert
result = "" + max(formula.substring(4, 6), formula.substring(7, 9));
else if (!formula.isEmpty()) {
try {
result = "" + calculate(formula); //geht nicht?
} catch(ArithmeticException ae) {
result = "exc.";
}
}
cells[row][col].setValue("" + result);
}
/**
* Method for calculating the sum of a rectangular block of cells, such as from A1 to B3.
* @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.
*/
private long sum(String startCellName, String endCellName) {
int startCellRow = getRow(startCellName);
int startCellCol = getCol(startCellName);
int endCellRow = getRow(endCellName);
int endCellCol = getCol(endCellName);
long res = 0;
for (int i = startCellRow; i <= endCellRow; i++) {
for (int j = startCellCol; j <= endCellCol; j++) {
res = res + (Integer.parseInt(cells[i][j].getValue()));
}
}
return res;
}
private long pro(String startCellName, String endCellName) {
int startCellRow = getRow(startCellName);
int startCellCol = getCol(startCellName);
int endCellRow = getRow(endCellName);
int endCellCol = getCol(endCellName);
long res = 0;
for (int i = startCellRow; i <= endCellRow; i++) {
for (int j = startCellCol; j <= endCellCol; j++) {
if (res == 0) {
res = Integer.parseInt(cells[i][j].getValue());
} else {
res = res * (Integer.parseInt(cells[i][j].getValue()));
}
}
}
return res;
}
private long min(String startCellName, String endCellName) {
int startCellRow = getRow(startCellName);
int startCellCol = getCol(startCellName);
int endCellRow = getRow(endCellName);
int endCellCol = getCol(endCellName);
long res = Long.MAX_VALUE;
long merker;
for (int i = startCellRow; i <= endCellRow; i++) {
for (int j = startCellCol; j <= endCellCol; j++) {
merker = Integer.parseInt(cells[i][j].getValue());
if (merker < res) {
res = merker;
}
}
}
return res;
}
private long max(String startCellName, String endCellName) {
int startCellRow = getRow(startCellName);
int startCellCol = getCol(startCellName);
int endCellRow = getRow(endCellName);
int endCellCol = getCol(endCellName);
long res = Long.MIN_VALUE;
long merker;
for (int i = startCellRow; i <= endCellRow; i++) {
for (int j = startCellCol; j <= endCellCol; j++) {
merker = Integer.parseInt(cells[i][j].getValue());
if (merker > res) {
res = merker;
}
}
}
return res;
}
private long mittelwert(String startCellName, String endCellName) {
int startCellRow = getRow(startCellName);
int startCellCol = getCol(startCellName);
int endCellRow = getRow(endCellName);
int endCellCol = getCol(endCellName);
long anzahl = 0;
long res = 0;
for (int i = startCellRow; i <= endCellRow; i++) {
for (int j = startCellCol; j <= endCellCol; j++) {
res = res + (Integer.parseInt(cells[i][j].getValue()));
anzahl++;
}
}
res = res/anzahl;
return res;
}
/**
* 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,
* minus, times, split only. An expression always starts with either a number or a cell name. If it
* continues, it is guaranteed that this is followed by an operator and either a number or a
* cell name again. It is NOT required to implement dot before dash or parentheses in formulas.
* @param formula The expression to be evaluated.
* @return The result calculated.
*/
private long calculate(String formula) throws ArithmeticException {
Matcher m = Pattern.compile("([A-Z][0-9]*)|[-\\+\\*/]|[0-9]*").matcher(formula);
long res = 0;
// TODO implement
int merker = 0;
int zaehler = 0;
int neue_zahl = 0;
// 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();
if (!s.isEmpty()) {
System.out.println(s);
zaehler++;
switch (zaehler){
case 1:
try {
res = Integer.parseInt(s);
}catch (Exception ignored){
res = Integer.parseInt(get(s));
}
break;
case 2:
switch(s) {
case "+":
merker = 1;
break;
case "-":
merker = 2;
break;
case "*":
merker = 3;
break;
case "/":
merker = 4;
break;
default:
System.out.println("ERROR");
break;
}
break;
case 3:
try {
neue_zahl = Integer.parseInt(s);
}catch (Exception ignored){
neue_zahl = Integer.parseInt(get(s));
}
res = rechne(res, merker, neue_zahl);
zaehler = 1;
break;
}
}
}
return res;
}
private long rechne(long a, int merker, int b) {
switch(merker){
case 1:
return a + b;
case 2:
return a - b;
case 3:
return a * b;
case 4:
return a / b;
default:
System.out.println("ERROR");
break;
}
return 0;
}
// -----
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(" ");
for (int i = 0; i < cells[0].length; i++) { // "[0]" -> nimmt sonst die falsche Länge!
sb.append(" " + (char)('A'+ i) + " | ");
}
int rc = 1;
for (Cell[] r : cells) {
sb.append(System.lineSeparator());
sb.append(String.format("%2s", rc++) + ": ");
for (Cell c : r) {
sb.append(c + " | ");
}
}
return sb.toString();
}
}