残念ながら、Double.parseDouble(s)または新しいBigDecimal(s)が最良の選択肢のようです。
ローカリゼーションの懸念を引用しますが、残念ながら、ユーザーによる指定なしですべてのロケールを確実にサポートする方法はありません。それは不可能です。
カンマとピリオドのどちらが最初に使用されているかを確認することで、使用されているスキームについて推論できる場合がありますが、両方が使用されている場合、これが常に可能であるとは限りません。より多くの状況で機能する可能性があるが、悪い結果をもたらす可能性のあるシステムに依存しようとするよりも、特定の状況で確実に機能することがわかっているシステムを用意する方がよい...
123,456という数字は何を表していますか?123456または123.456?
ユーザーが指定したロケールに応じて、コンマ、スペース、またはピリオドを削除するだけです。デフォルトでは、スペースとコンマを削除します。厳密にしたい場合は、コンマまたはスペースのみを削除し、両方は削除せず、ピリオドがある場合はピリオドの前のみを削除します。また、3つに適切に配置されているかどうかを手動で確認するのも非常に簡単です。実際、ここではカスタムパーサーが最も簡単な場合があります。
これが概念実証のビットです。それは少し(非常に)厄介ですが、私はそれがうまくいくと思います、そしてあなたはとにかくアイデアを得るでしょう:)。
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を失敗させることができます。
また、これを使用してNumberFormatを適切に拡張することもお勧めします。解析された数値用のgetSeparator()と、目的の出力形式を提供するためのsetSeparatorがあります...この種のローカリゼーションは処理されますが、小数の「、」をサポートするには、さらに多くの作業を行う必要があります。