К сожалению, Double.parseDouble (s) или новые BigDecimal (s) кажутся вашими лучшими вариантами.
Вы цитируете проблемы локализации, но, к сожалению, в любом случае нет надежной поддержки всех локалей без спецификации пользователя. Это просто невозможно.
Иногда вы можете рассуждать об используемой схеме, посмотрев, используются ли вначале запятые или точки, если используются оба, но это не всегда возможно, так зачем даже пытаться? Лучше иметь систему, которая, как вы знаете, надежно работает в определенных ситуациях, чем пытаться полагаться на систему, которая может работать в большем количестве ситуаций, но также может давать плохие результаты ...
Что означает число 123 456? 123456 или 123,456?
Просто удалите запятые, пробелы или точки в зависимости от локали, указанной пользователем. По умолчанию для удаления пробелов и запятых. Если вы хотите сделать его более строгим, то удаляйте только запятые ИЛИ пробелы, а не оба, и только до того периода, если он есть. Также должно быть довольно легко проверить вручную, правильно ли они расположены в тройках. На самом деле пользовательский парсер может быть проще всего здесь.
Вот немного подтверждения концепции. Это немного (очень) грязно, но я считаю, что это работает, и вы все равно поймете идею:).
public class StrictNumberParser {
public double parse(String numberString) throws NumberFormatException {
numberString = numberString.trim();
char[] numberChars = numberString.toCharArray();
Character separator = null;
int separatorCount = 0;
boolean noMoreSeparators = false;
for (int index = 1; index < numberChars.length; index++) {
char character = numberChars[index];
if (noMoreSeparators || separatorCount < 3) {
if (character == '.') {
if (separator != null) {
throw new NumberFormatException();
} else {
noMoreSeparators = true;
}
} else if (separator == null && (character == ',' || character == ' ')) {
if (noMoreSeparators) {
throw new NumberFormatException();
}
separator = new Character(character);
separatorCount = -1;
} else if (!Character.isDigit(character)) {
throw new NumberFormatException();
}
separatorCount++;
} else {
if (character == '.') {
noMoreSeparators = true;
} else if (separator == null) {
if (Character.isDigit(character)) {
noMoreSeparators = true;
} else if (character == ',' || character == ' ') {
separator = new Character(character);
} else {
throw new NumberFormatException();
}
} else if (!separator.equals(character)) {
throw new NumberFormatException();
}
separatorCount = 0;
}
}
if (separator != null) {
if (!noMoreSeparators && separatorCount != 3) {
throw new NumberFormatException();
}
numberString = numberString.replaceAll(separator.toString(), "");
}
return Double.parseDouble(numberString);
}
public void testParse(String testString) {
try {
System.out.println("result: " + parse(testString));
} catch (NumberFormatException e) {
System.out.println("Couldn't parse number!");
}
}
public static void main(String[] args) {
StrictNumberParser p = new StrictNumberParser();
p.testParse("123 45.6");
p.testParse("123 4567.8");
p.testParse("123 4567");
p.testParse("12 45");
p.testParse("123 456 45");
p.testParse("345.562,346");
p.testParse("123 456,789");
p.testParse("123,456,789");
p.testParse("123 456 789.52");
p.testParse("23,456,789");
p.testParse("3,456,789");
p.testParse("123 456.12");
p.testParse("1234567.8");
}
}
РЕДАКТИРОВАТЬ: очевидно, что это должно быть расширено для распознавания научной нотации, но это должно быть достаточно просто, особенно если вам не нужно фактически проверять что-либо после e, вы можете просто позволить parseDouble fail, если он плохо сформирован .
Также может быть хорошей идеей правильно расширить NumberFormat с этим. иметь getSeparator () для разобранных чисел и setSeparator для предоставления желаемого выходного формата ... Этот вид заботится о локализации, но опять же нужно проделать дополнительную работу для поддержки ',' для десятичных дробей ...