В Java я пытаюсь выяснить, является ли значение, содержащееся в строке, двойным или нет?
Как узнать, является ли значение, содержащееся в строке, двойным или нет
Ответ 1
boolean isDouble(String str) {
try {
Double.parseDouble(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
Ответ 2
В для Double
есть примечание:
[...] Чтобы избежать вызова этого метода с недопустимой строкой и сбрасыванием
NumberFormatException
, приведенное ниже регулярное выражение может использоваться для отображения входной строки: [...]
Окончательный вид следующих регулярных выражений довольно длинный:
[\x00-\x20]*[+-]?(NaN|Infinity|((((\p{Digit}+)(\.)?((\p{Digit}+)?)([eE][+-]?(\p{Digit}+))?)|(\.((\p{Digit}+))([eE][+-]?(\p{Digit}+))?)|(((0[xX](\p{XDigit}+)(\.)?)|(0[xX](\p{XDigit}+)?(\.)(\p{XDigit}+)))[pP][+-]?(\p{Digit}+)))[fFdD]?))[\x00-\x20]*
Используя этот метод, вы можете легко исключить некоторые специальные удвоения, такие как Infinity
и NaN
, которые оба признаны Double.parseDouble
. Например, например:
String regExp = "[\\x00-\\x20]*[+-]?(((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*";
boolean matches = yourString.matches(regExp);
Ответ 3
Вы можете создать Scanner(String)
и использовать hasNextDouble()
. Из своего javadoc:
Возвращает
true
, если следующий токен в этом входе сканера может быть интерпретируется как двойное значение, используя методnextDouble()
. Сканер не продвигается мимо каких-либо входных данных.
Например, этот фрагмент:
List<String> values = Arrays.asList("foo", "1", "2.3", "1f", "0.2d", "3.14");
for (String source : values) {
Scanner scanner = new Scanner(source);
System.out.println(String.format("%4s: %s", source, scanner.hasNextDouble()));
}
Произведет следующий вывод:
foo: false 1: true 2.3: true 1f: false 0.2d: false 3.14: true
Ответ 4
Использование Scanner
будет значительно медленнее, чем при использовании Double.parseDouble(String s)
.
private static Random rand = new Random();
private static final String regExp = "[\\x00-\\x20]*[+-]?(((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*";
private static final Pattern pattern = Pattern.compile(regExp);
public static void main(String[] args) {
int trials = 50000;
String[] values = new String[trials];
// initialize the array
// about half the values will be parsable as double
for( int i = 0; i < trials; ++i ) {
double d = rand.nextDouble();
boolean b = rand.nextBoolean();
values[i] = (b ? "" : "abc") + d;
}
long start = System.currentTimeMillis();
int parseCount = 0;
for( int i = 0; i < trials; ++i ) {
if( isDoubleParse(values[i]) ) {
parseCount++;
}
}
long end = System.currentTimeMillis();
long elapsed = end - start;
System.out.println("Elapsed time parsing: " + elapsed + " ms");
System.out.println("Doubles: " + parseCount);
// reset the timer for the next run
start = System.currentTimeMillis();
int scanCount = 0;
for( int i = 0; i < trials; ++i ) {
if( isDoubleScan(values[i]) ) {
scanCount++;
}
}
end = System.currentTimeMillis();
elapsed = end - start;
System.out.println("Elapsed time scanning: " + elapsed + " ms");
System.out.println("Doubles: " + scanCount);
// reset the timer for the next run
start = System.currentTimeMillis();
int regexCount = 0;
for( int i = 0; i < trials; ++i ) {
if( isDoubleRegex(values[i]) ) {
regexCount++;
}
}
end = System.currentTimeMillis();
elapsed = end - start;
System.out.println("Elapsed time regex (naive): " + elapsed + " ms");
System.out.println("Doubles: " + naiveRegexCount);
// reset the timer for the next run
start = System.currentTimeMillis();
int compiledRegexCount = 0;
for( int i = 0; i < trials; ++i ) {
if( isDoubleCompiledRegex(values[i]) ) {
compiledRegexCount++;
}
}
end = System.currentTimeMillis();
elapsed = end - start;
System.out.println("Elapsed time regex (compiled): " + elapsed + " ms");
System.out.println("Doubles: " + compiledRegexCount);
}
public static boolean isDoubleParse(String s) {
if( s == null ) return false;
try {
Double.parseDouble(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}
public static boolean isDoubleScan(String s) {
Scanner scanner = new Scanner(s);
return scanner.hasNextDouble();
}
public static boolean isDoubleRegex(String s) {
return s.matches(regExp);
}
public static boolean isDoubleCompiledRegex(String s) {
Matcher m = pattern.matcher(s);
return m.matches();
}
Когда я запускаю код выше, я получаю следующий вывод:
Истекшее время разбора: 235 мс
Парные разряды: 24966
Истекшее время сканирования: 31358 мс
Парные разряды: 24966
Истекшее время регулярного выражения (наивное): 1829 ms
Парные разряды: 24966
Игре прошедшего времени (скомпилировано): 109 мс
Парный разряд: 24966
Метод регулярного выражения выполняется довольно быстро, учитывая сложность регулярного выражения, но все же не так быстро, как просто синтаксический анализ с использованием Double.parseDouble(s)
. Как отмечено в комментариях, есть несколько значений, таких как NaN
, которые проходят через парсер, который, вероятно, не должен.
Обновление:
Предварительная компиляция регулярного выражения, предложенная @Gabe, имеет большое значение. Скомпилированный регулярный метод теперь является явным победителем.
Ответ 5
public boolean isDouble(String value) {
try {
Double.parseDouble(value);
return true;
} catch (NumberFormatException e) {
return false;
}
}
Ответ 6
Вы можете использовать класс util из Apache Commons Lang:
NumberUtils.isNumber(aString);
Он недействителен и не требует использования блока try-catch.
Примечание: для парсинга двойников он работает, если десятичный разделитель является точкой .
Изменить: isNumber устарел и будет удален из Lang 4.0
Лучше использовать:
NumberUtils.isCreatable(aString);
Ответ 7
Вы можете попытаться проанализировать его с помощью Double.parseDouble(String s)
Это приведет к возврату double, если синтаксический анализ был успешным и исключение, если оно не обрабатывается.
Итак, вы можете обернуть все это в функцию, содержащую try-catch, и вернуть false, если у вас есть исключение или true, если вы получили фактическое значение.
Ответ 8
Я бы предложил следующее:
try {
d = Double.parseDouble(myString);
}
catch (NumberFormatException ex) {
// Do something smart here...
}
Ответ 9
Вы можете попробовать сравнить его с регулярным выражением, как описано здесь: http://www.regular-expressions.info/floatingpoint.html
Похожие вопросы:
Regex для анализа номеров с плавающей запятой Как определить число с плавающей запятой, используя регулярное выражение
Ответ 10
Другие предположили, что вы также можете знать, что вход НЕ выражен как целое. В зависимости от ваших требований это может сделать работу быстрой и грязной:
public static void main(String[] args) throws Exception {
System.out.println(isNonIntegerDouble("12")); //false
System.out.println(isNonIntegerDouble("12.1")); //true
System.out.println(isNonIntegerDouble("12.0")); //true
}
public static boolean isNonIntegerDouble(String in) {
try {
Double.parseDouble(in);
} catch (NumberFormatException nfe) {
return false;
}
try {
new BigInteger(in);
} catch (NumberFormatException nfe) {
return true;
}
return false;
}
В этот момент я считаю, что сопоставление строк было бы более подходящим выбором.
Ответ 11
В строке можно использовать следующее регулярное выражение:
[-+]?[0-9]*\.?[0-9]*
и посмотрите, совпадает ли он.
Ответ 12
Я изменил метод Jonas 'isInteger(), чтобы придумать метод isDecimal() для моего собственного проекта, и я перечисляю приведенные ниже коды.
Может быть, кто-то может изменить, добавьте больше кодов, чтобы различать double и float.
Он должен выглядеть довольно быстро и, вероятно, лучше, чем регулярное выражение, хотя я не проверял. Единственный недостаток - это неправильная работа в случае переполнения и т.д.
Обратите внимание, что я ссылаюсь на сообщение Билла в Каков наилучший способ проверить, является ли String целочисленным в Java?
public boolean isDecimal(String str) {
if (str == null) {
return false;
}
int length = str.length();
if (length == 1 ) {
return false;
}
int i = 0;
if (str.charAt(0) == '-') {
if (length < 3) {
return false;
}
i = 1;
}
int numOfDot = 0;
for (; i < length; i++) {
char c = str.charAt(i);
if (c == '.')
numOfDot++;
else if (c == '/')
return false;
else if (c < '.' || c > '9') {
return false;
}
}
if (numOfDot != 1 )
return false;
return true;
}
Ответ 13
Если бы вы могли найти способ выделения числа из строки, возможно, используя метод split. И скажем num[1] = 25;
, тогда вы можете сделать что-то подобное, чтобы проверить, есть ли у него двойной.
boolean isDouble;
if(num[1].contains(".")){
isDouble = true;
}
else{
isDouble = false;
}
Ответ 14
Мы должны обработать NumberFormatException и исключение нулевого указателя, чтобы проверить, является ли данная строка числовой или буквенно-цифровой
public static boolean isNumeric(String strNum) {
try {
Double.parseDouble(strNum);
} catch (NumberFormatException | NullPointerException nfe) {
return false;
}
return true;
}
Ответ 15
private boolean checkIsNumber(Object value) {
try {
boolean isNumber = NumberUtils.isNumber((String) value);
if (!isNumber) {
Double.parseDouble((String) value);
}
} catch (Exception e) {
return false;
}
return true;
}
Ответ 16
Try:
boolean isDouble;
try
{
Double.parseDouble("1.2");
isDouble = true;
}catch(Exception e){
isDouble = false;
}
Хотя обычно не рекомендуется использовать исключения, такие как условные обозначения.
Ответ 17
public boolean isDouble( String input )
{
try
{
Double.parseDouble( input );
return true;
}
catch( Exception e)
{
return false;
}
}