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 SEP = 0;
const INT = 1;
const FLOAT = 2;
const EXP = 3;
var state = SEP;
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 = INT;
number = current;
newNumber();
continue;
}
// parse until next number
if (state == SEP) {
// eat whitespace
if (RE["WHITESPACE"].hasMatch(current)) {
continue;
}
// start new number
if (RE["DIGIT"].hasMatch(current) || RE["SIGN"].hasMatch(current)) {
state = INT;
number = current;
continue;
}
if (RE["POINT"].hasMatch(current)) {
state = FLOAT;
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 == INT) {
if (RE["DIGIT"].hasMatch(current)) {
number += current;
continue;
}
if (RE["POINT"].hasMatch(current)) {
number += current;
state = FLOAT;
continue;
}
if (RE["EXP"].hasMatch(current)) {
state = EXP;
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 == FLOAT) {
if (RE["DIGIT"].hasMatch(current)) {
number += current;
continue;
}
if (RE["EXP"].hasMatch(current)) {
state = EXP;
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 == EXP) {
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 = SEP;
seenComma = false;
} else if (RE["COMMA"].hasMatch(current)) {
newNumber();
state = SEP;
seenComma = true;
} else if (RE["SIGN"].hasMatch(current)) {
newNumber();
state = INT;
number = current;
} else if (RE["POINT"].hasMatch(current)) {
newNumber();
state = FLOAT;
number = current;
} else {
throwSyntaxError(current, i, result);
}
}
// add the last number found (if any)
newNumber();
return result;
}