package org.geogebra.common.gui.view.spreadsheet;
import org.geogebra.common.main.App;
import org.geogebra.common.util.opencsv.CSVException;
import org.geogebra.common.util.opencsv.CSVParser;
import com.google.gwt.regexp.shared.RegExp;
/**
* Utility class with methods to handle importing data into the spreadsheet.
*
* @author G. Sturr
*
*/
public class DataImport {
static CSVParser commaParser, tabParser;
/*
* disabled option to change as we don't want commas when pasting from
* spreadsheet into other parts of GeoGebra eg input bar also see
* CopyPasteCutD.copy()
*/
final static String decimalSeparator = ".";
/**
* Parses external non-ggb data.
*
* @param app
* @param source
* string to be parsed
* @param separator
* separator[0] = decimal separator, separator[1] = grouping
* separator; if null then defaults for the locale will be used
* @param isCSV
* true = comma delimited parsing, false = tab delimited parsing
* @return 2D string array with values formatted for the spreadsheet.
*/
public static String[][] parseExternalData(App app, String source,
boolean isCSV) {
String[][] data;
// ignore isCSV parameter, just check for <Tab> \t
if (source.indexOf('\t') == -1) {
// convert the given string into a 2D array defined by comma
// delimiters
data = parseCSVdata(source);
} else {
// convert the given string into a 2D array defined by tab
// delimiters
data = parseTabData(source);
}
int maxLength = 0;
for (int i = 0; i < data.length; i++) {
if (data[i].length > maxLength) {
maxLength = data[i].length;
}
}
// copy the data into new array
// so that we return an array with all rows the same length
String[][] dataRet = new String[data.length][maxLength];
// traverse the 2D array to prepare strings for the spreadsheet
for (int i = 0; i < data.length; i++) {
for (int k = 0; k < maxLength; k++) {
if (data[i].length > k) {
// prevent empty string conversion to "null"
if (data[i][k].length() == 0) {
data[i][k] = " ";
}
// remove localized number formatting
// e.g. 3,400 ---> 3400 or 3,4567 --> 3.4567
dataRet[i][k] = adjustNumberString(data[i][k]);
} else {
dataRet[i][k] = " ";
}
}
}
return dataRet;
}
private static CSVParser getCommaParser() {
if (commaParser == null) {
commaParser = new CSVParser();
}
return commaParser;
}
private static CSVParser getTabParser() {
if (tabParser == null) {
tabParser = new CSVParser('\t');
}
return tabParser;
}
private static String[][] parseCSVdata(String input) {
// split lines using "\r?\n|\r" to handle win/linux/mac cases
String[] lines = input.split("\r?\n|\r", -1);
if (lines.length == 0) {
return null;
}
// create 2D data array
int numLines = lines[lines.length - 1].length() == 0 ? lines.length - 1
: lines.length;
String[][] data = new String[numLines][];
// parse each line and add to data array
for (int i = 0; i < numLines; ++i) {
try {
data[i] = getCommaParser().parseLineMulti(lines[i]);
} catch (CSVException e) {
e.printStackTrace();
return null;
}
}
return data;
}
public static String[][] parseTabData(String input) {
// Application.debug("parse data: " + input);
// split lines using "\r?\n|\r" to handle win/linux/mac cases
String[] lines = input.split("\r?\n|\r", -1);
if (lines.length == 0) {
return null;
}
// create 2D data array
int numLines = lines[lines.length - 1].length() == 0 ? lines.length - 1
: lines.length;
String[][] data = new String[numLines][];
// parse each line and add to data array
for (int i = 0; i < numLines; ++i) {
// trim() removes tabs which we need
// lines[i] = StringUtil.trimSpaces(lines[i]);
try {
// .out.println("parse line: " + lines[i]);
data[i] = getTabParser().parseLineMulti(lines[i]);
} catch (CSVException e) {
e.printStackTrace();
}
}
return data;
}
// match numbers with commas every 3 digits eg 1,234
// 1,234,567
// 12,456
// 123,566
// -123,566
// don't match
// 123
// 12
// 1
// 0,123
// 123,456789
final private static RegExp regex = RegExp
.compile("^-?\\d?\\d?\\d,(\\d\\d\\d,)*\\d\\d\\d$");
/**
* Returns an unformatted number string (e.g. "1,234,567" --> "1234567")
* otherwise the comma is replaced with a . eg 1,234567 -> 1.234567
*
* Note: 1,234 is ambiguous, convert to 1234
*
* if the given string is a number that Geogebra's parser recognizes. If
* cannot be parsed to a number, then the original string is returned.
*/
private static String adjustNumberString(String s) {
if (s == null || "".equals(s)) {
return s;
}
String s2 = s;
// System.out.println("====================");
// System.out.println(decimalSeparator + " | " + groupingSeparator);
// System.out.println("test string: " + s);
if (regex.test(s)) {
// change 1,234,567 to 1234567
s2 = s2.replace(",", "");
} else {
// change 0,12345 to 012345
s2 = s2.replace(",", ".");
}
// System.out.println("converted string: " + s2);
// System.out.println("is number: " + RelativeCopy.isNumber(s2));
if (RelativeCopy.isNumber(s2)) {
return s2;
}
return s;
}
}