parseFloats method
List<double>
parseFloats(
- dynamic input, [
- dynamic flags,
- dynamic stride
])
Implementation
List<double> parseFloats(input, [flags, stride]) {
if (input is! String) {
throw ('Invalid input: ${input.runtimeType} ');
}
// Character groups
Map<String, dynamic> re = {
"SEPARATOR": RegExp(r"[ \t\r\n\,.\-+]"),
"WHITESPACE": RegExp(r"[ \t\r\n]"),
"DIGIT": RegExp(r"[\d]"),
"SIGN": RegExp(r"[-+]"),
"POINT": RegExp(r"\."),
"COMMA": RegExp(r","),
"EXP": RegExp(r"e", caseSensitive: false),
"FLAGS": RegExp(r"[01]")
};
// States
const sepValue = 0;
const intValue = 1;
const floatValue = 2;
const expValue = 3;
var state = sepValue;
var seenComma = true;
var number = '', exponent = '';
List<double> result = [];
throwSyntaxError(current, i, partial) {
var error = ('Unexpected character "$current" at index $i.');
throw (error);
}
newNumber() {
if (number != '') {
if (exponent == '') {
result.add(double.parse(number));
} else {
result.add(double.parse(number) * Math.pow(10, double.parse(exponent)));
}
}
number = '';
exponent = '';
}
String current;
var length = input.length;
for (var i = 0; i < length; i++) {
current = input[i];
// check for flags
if (flags is List && flags.contains(result.length % stride) && re["FLAGS"].hasMatch(current)) {
state = intValue;
number = current;
newNumber();
continue;
}
// parse until next number
if (state == sepValue) {
// eat whitespace
if (re["WHITESPACE"].hasMatch(current)) {
continue;
}
// start new number
if (re["DIGIT"].hasMatch(current) || re["SIGN"].hasMatch(current)) {
state = intValue;
number = current;
continue;
}
if (re["POINT"].hasMatch(current)) {
state = floatValue;
number = current;
continue;
}
// throw on double commas (e.g. "1, , 2")
if (re["COMMA"].hasMatch(current)) {
if (seenComma) {
throwSyntaxError(current, i, result);
}
seenComma = true;
}
}
// parse integer part
if (state == intValue) {
if (re["DIGIT"].hasMatch(current)) {
number += current;
continue;
}
if (re["POINT"].hasMatch(current)) {
number += current;
state = floatValue;
continue;
}
if (re["EXP"].hasMatch(current)) {
state = expValue;
continue;
}
// throw on double signs ("-+1"), but not on sign as separator ("-1-2")
if (re["SIGN"].hasMatch(current) && number.length == 1 && re["SIGN"].hasMatch(number[0])) {
throwSyntaxError(current, i, result);
}
}
// parse decimal part
if (state == floatValue) {
if (re["DIGIT"].hasMatch(current)) {
number += current;
continue;
}
if (re["EXP"].hasMatch(current)) {
state = expValue;
continue;
}
// throw on double decimal points (e.g. "1..2")
if (re["POINT"].hasMatch(current) && number[number.length - 1] == '.') {
throwSyntaxError(current, i, result);
}
}
// parse exponent part
if (state == expValue) {
if (re["DIGIT"].hasMatch(current)) {
exponent += current;
continue;
}
if (re["SIGN"].hasMatch(current)) {
if (exponent == '') {
exponent += current;
continue;
}
if (exponent.length == 1 && re["SIGN"].hasMatch(exponent)) {
throwSyntaxError(current, i, result);
}
}
}
// end of number
if (re["WHITESPACE"].hasMatch(current)) {
newNumber();
state = sepValue;
seenComma = false;
} else if (re["COMMA"].hasMatch(current)) {
newNumber();
state = sepValue;
seenComma = true;
} else if (re["SIGN"].hasMatch(current)) {
newNumber();
state = intValue;
number = current;
} else if (re["POINT"].hasMatch(current)) {
newNumber();
state = floatValue;
number = current;
} else {
throwSyntaxError(current, i, result);
}
}
// add the last number found (if any)
newNumber();
return result;
}