Как проверить, является ли строка числовой в Java

720

Как бы вы проверили, была ли строка числом до ее разбора?

  • 33
    Все решения, предлагаемые с регулярными выражениями, не будут работать для шестнадцатеричных чисел.
  • 0
    и передача пустой строки в функции match (...) вызовет исключение NullPointer.
Показать ещё 4 комментария
Теги:
string
numeric

39 ответов

577
Лучший ответ

С Apache Commons Lang 3.5 и выше: NumberUtils.isCreatable или StringUtils.isNumeric.

С Apache Commons Lang 3.4 и ниже: NumberUtils.isNumber или StringUtils.isNumeric.

Вы также можете использовать StringUtils.isNumericSpace который возвращает true для пустых строк и игнорирует внутренние пробелы в строке. Другим способом является использование StringUtils.isParsable который в основном проверяет, является ли число StringUtils.isParsable для StringUtils.isParsable в соответствии с Java. (Связанные javadocs содержат подробные примеры для каждого метода.)

  • 97
    +1 Зачем заново изобретать колесо.
  • 54
    StringUtils.isNumeric() вероятно, здесь не подходит, так как он только проверяет, является ли строка последовательностью цифр. Подойдет для большинства целых, но не для чисел с десятичными числами, разделителями групп и т. Д.
Показать ещё 11 комментариев
859

Обычно это делается с помощью простой пользовательской функции (т.е. функция Roll-your-own "isNumeric").

Что-то вроде:

public static boolean isNumeric(String str)  
{  
  try  
  {  
    double d = Double.parseDouble(str);  
  }  
  catch(NumberFormatException nfe)  
  {  
    return false;  
  }  
  return true;  
}

Однако, если вы вызываете эту функцию много, и вы ожидаете, что многие из проверок будут терпеть неудачу из-за того, что не будет числа, производительность этого механизма будет невелика, поскольку вы полагаетесь на исключения, которые бросаются на каждый сбой, что является довольно дорогостоящей операцией.

Альтернативным подходом может быть использование регулярного выражения для проверки действительности числа:

public static boolean isNumeric(String str)
{
  return str.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.
}

Однако будьте осторожны с вышеупомянутым механизмом RegEx, поскольку он будет терпеть неудачу, если вы используете неарабские цифры (например, цифры, отличные от 0 до 9). Это связано с тем, что часть "\ d" RegEx будет соответствовать только [0-9] и эффективно не воспринимается на международном уровне. (Спасибо OregonGhost за это!)

Или еще одна альтернатива - использовать встроенный Java-объект java.text.NumberFormat Java, чтобы увидеть, после синтаксического анализа строки позиция парсера находится в конце строки. Если это так, мы можем предположить, что вся строка является числовой:

public static boolean isNumeric(String str)
{
  NumberFormat formatter = NumberFormat.getInstance();
  ParsePosition pos = new ParsePosition(0);
  formatter.parse(str, pos);
  return str.length() == pos.getIndex();
}
  • 7
    \ D в Java Regex соответствует только латинским цифрам? Если это похоже на регулярные выражения .NET, вы столкнетесь с проблемой с другими (например, арабскими) цифрами, как описано здесь: blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
  • 0
    @OregonGhost - Упс .. Хороший улов. Ты прав. \ d будет совпадать только с латинскими цифрами (т. е. от 0 до 9) и не будет совпадать с арабскими. Я отредактировал свой пост, чтобы прояснить это. Спасибо!
Показать ещё 22 комментария
132

если вы находитесь на android, вы должны использовать:

android.text.TextUtils.isDigitsOnly(CharSequence str)

документацию можно найти здесь

держать его простым. в основном каждый может "перепрограммировать" (то же самое).

  • 6
    Это не будет работать для 123.456; (
  • 3
    @ kape123 :) уверен, что "123.456" не содержит цифр.
Показать ещё 3 комментария
117

Как отметил @CraigTP в своем превосходном ответе, у меня также есть аналогичные проблемы с производительностью при использовании Exceptions для проверки того, является ли строка числовой или нет. Поэтому я заканчиваю разделение строки и использую java.lang.Character.isDigit().

public static boolean isNumeric(String str)
{
    for (char c : str.toCharArray())
    {
        if (!Character.isDigit(c)) return false;
    }
    return true;
}

Согласно Javadoc, Character.isDigit(char) будет правильно распознавать нелатинские цифры. С точки зрения производительности, я думаю, что простое N количество сравнений, где N - количество символов в строке, было бы более вычислительно эффективным, чем выполнение соответствия регулярных выражений.

ОБНОВЛЕНИЕ: Как указал Жан-Франсуа Корбетт в комментарии, вышеуказанный код будет только проверять положительные целые числа, которые охватывают большинство моих вариантов использования. Ниже приведен обновленный код, который корректно проверяет десятичные числа в соответствии с языковой установкой по умолчанию, используемой в вашей системе, с предположением, что разделитель десятичных знаков встречается только один раз в строке.

public static boolean isStringNumeric( String str )
{
    DecimalFormatSymbols currentLocaleSymbols = DecimalFormatSymbols.getInstance();
    char localeMinusSign = currentLocaleSymbols.getMinusSign();

    if ( !Character.isDigit( str.charAt( 0 ) ) && str.charAt( 0 ) != localeMinusSign ) return false;

    boolean isDecimalSeparatorFound = false;
    char localeDecimalSeparator = currentLocaleSymbols.getDecimalSeparator();

    for ( char c : str.substring( 1 ).toCharArray() )
    {
        if ( !Character.isDigit( c ) )
        {
            if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
            {
                isDecimalSeparatorFound = true;
                continue;
            }
            return false;
        }
    }
    return true;
}
  • 2
    Разве десятичный разделитель также не приведет к сбою?
  • 1
    @ Жан-Франсуа Корбетт: Хорошо, я обновил код новым, который принимает десятичные разделители.
Показать ещё 5 комментариев
80

Ява-выражения Java 8.

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
  • 3
    Вы также можете использовать ссылку на метод: someString.chars (). AllMatch (Character :: isDigit)
  • 3
    Приятно, но все же он изобретает велосипед как почти все «решения» здесь. Кроме того, терпит неудачу при 'нуле' (как почти все другие).
Показать ещё 7 комментариев
40

Библиотека Google Guava предоставляет хороший вспомогательный метод для этого: Ints.tryParse. Вы используете его как Integer.parseInt, но он возвращает null, а не бросает исключение, если строка не анализирует действительное целое число. Обратите внимание, что он возвращает Integer, а не int, поэтому вам нужно преобразовать /autobox его обратно в int.

Пример:

String s1 = "22";
String s2 = "22.2";
Integer oInt1 = Ints.tryParse(s1);
Integer oInt2 = Ints.tryParse(s2);

int i1 = -1;
if (oInt1 != null) {
    i1 = oInt1.intValue();
}
int i2 = -1;
if (oInt2 != null) {
    i2 = oInt2.intValue();
}

System.out.println(i1);  // prints 22
System.out.println(i2);  // prints -1

Однако, с текущей версии - Guava r11 - он по-прежнему отмечен @Beta.

Я не сравнивал это. Глядя на исходный код, есть некоторые накладные расходы из многих проверок здравомыслия, но в конце они используют Character.digit(string.charAt(idx)), похожий, но немного отличный от ответа от @Ibrahim выше. В их реализации нет покрытий обработки исключений.

28

Не используйте исключения для проверки ваших значений. Используйте Util libs вместо apache NumberUtils:

NumberUtils.isNumber(myStringValue);

Изменить:

Обратите внимание, что если ваша строка начинается с 0, NumberUtils будет интерпретировать ваше значение как шестнадцатеричное.

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
  • 7
    Принятый ответ тремя годами ранее уже охватывал Number.isNumber() .
  • 0
    Я так не думаю. Он был обновлен или оп изменил принятый ответ. Я помню, что принятый ответ не покрывал NumberUtils, поэтому я добавил свой ответ. Но спасибо за комментарий
Показать ещё 2 комментария
21

Почему все, кто настаивает на решениях exception/regex?

В то время как я могу понять, что большинство людей отлично справляются с использованием try/catch, если вы хотите часто это делать... это может быть чрезвычайно облагаемым налогом.

То, что я здесь делал, это взять регулярное выражение, методы parseNumber() и метод поиска массива, чтобы узнать, какой из них наиболее эффективен. На этот раз я только посмотрел на целые числа.

public static boolean isNumericRegex(String str) {
    if (str == null)
        return false;
    return str.matches("-?\\d+");
}

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    char[] data = str.toCharArray();
    if (data.length <= 0)
        return false;
    int index = 0;
    if (data[0] == '-' && data.length > 1)
        index = 1;
    for (; index < data.length; index++) {
        if (data[index] < '0' || data[index] > '9') // Character.isDigit() can go here too.
            return false;
    }
    return true;
}

public static boolean isNumericException(String str) {
    if (str == null)
        return false;
    try {  
        /* int i = */ Integer.parseInt(str);
    } catch (NumberFormatException nfe) {  
        return false;  
    }
    return true;
}

Результаты в скорости, которые я получил, были:

Done with: for (int i = 0; i < 10000000; i++)...

With only valid numbers ("59815833" and "-59815833"):
    Array numeric took 395.808192 ms [39.5808192 ns each]
    Regex took 2609.262595 ms [260.9262595 ns each]
    Exception numeric took 428.050207 ms [42.8050207 ns each]
    // Negative sign
    Array numeric took 355.788273 ms [35.5788273 ns each]
    Regex took 2746.278466 ms [274.6278466 ns each]
    Exception numeric took 518.989902 ms [51.8989902 ns each]
    // Single value ("1")
    Array numeric took 317.861267 ms [31.7861267 ns each]
    Regex took 2505.313201 ms [250.5313201 ns each]
    Exception numeric took 239.956955 ms [23.9956955 ns each]
    // With Character.isDigit()
    Array numeric took 400.734616 ms [40.0734616 ns each]
    Regex took 2663.052417 ms [266.3052417 ns each]
    Exception numeric took 401.235906 ms [40.1235906 ns each]

With invalid characters ("5981a5833" and "a"):
    Array numeric took 343.205793 ms [34.3205793 ns each]
    Regex took 2608.739933 ms [260.8739933 ns each]
    Exception numeric took 7317.201775 ms [731.7201775 ns each]
    // With a single character ("a")
    Array numeric took 291.695519 ms [29.1695519 ns each]
    Regex took 2287.25378 ms [228.725378 ns each]
    Exception numeric took 7095.969481 ms [709.5969481 ns each]

With null:
    Array numeric took 214.663834 ms [21.4663834 ns each]
    Regex took 201.395992 ms [20.1395992 ns each]
    Exception numeric took 233.049327 ms [23.3049327 ns each]
    Exception numeric took 6603.669427 ms [660.3669427 ns each] if there is no if/null check

Отказ от ответственности: я не утверждаю, что эти методы на 100% оптимизированы, они просто для демонстрации данных

Исключения выиграны, если и только если число равно 4 символам или меньше, и каждая строка всегда является числом... в этом случае, почему даже есть чек?

Короче говоря, очень сложно, если вы часто сталкиваетесь с недопустимыми числами с помощью try/catch, что имеет смысл. Важным правилом, которым я всегда придерживаюсь, является НИКОГДА не использовать try/catch для потока программы. Это пример.

Интересно, что простой, если char < 0 || > 9 было чрезвычайно просто писать, легко запоминаться (и должно работать на нескольких языках) и выигрывает почти все тестовые сценарии.

Единственным недостатком является то, что я предполагаю, что Integer.parseInt() может обрабатывать не ASCII-номера, тогда как метод поиска массива не работает.


Для тех, кто задавался вопросом, почему я сказал, что легко запомнить массив символов, если вы не знаете никаких отрицательных признаков, вы можете легко уйти от чего-то сжатого, как это:

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    for (char c : str.toCharArray())
        if (c < '0' || c > '9')
            return false;
    return true;

Наконец, в качестве заключительной заметки, мне было интересно узнать оператора-ассистента в принятом примере со всеми голосами. Добавление в присваивание

double d = Double.parseDouble(...)

не только бесполезен, поскольку вы даже не используете его, но он тратит время обработки и увеличивает время выполнения на несколько наносекунд (что привело к увеличению тестов на 100-200 мс). Я не понимаю, почему кто-то это сделает, поскольку на самом деле это дополнительная работа для снижения производительности.

Вы подумали бы, что это будет оптимизировано... хотя, возможно, я должен проверить байт-код и посмотреть, что делает компилятор. Это не объясняет, почему это всегда показалось мне более длинным, хотя если оно каким-то образом оптимизировано... поэтому я задаюсь вопросом, что происходит. В качестве примечания: по длине я имею в виду запуск теста для 10000000 итераций, и запуск этой программы несколько раз (10x +) всегда показывал, что она медленнее.

EDIT: Обновлен тест для Character.isDigit()

  • 4
    Разве это не компилирует новое регулярное выражение каждый раз? Это не кажется очень эффективным.
  • 0
    @SamuelEdwinWard Вот и вся причина, по которой я сделал этот пост ... Пример регулярного выражения использовал ответы других людей и показал, насколько он неэффективен. Даже если вы попытаетесь выполнить регулярное выражение с предварительной компиляцией заранее и только с его использованием, разница во времени составит: 2587 мс для регулярного выражения, которое я отправил от других пользователей, 950 мс при предварительной компиляции, 144 мс при выполнении этого как числовой массив (для 1 миллиона итераций одной и той же строки). Компиляция заблаговременно, очевидно, помогла бы, но, к сожалению, она все еще значительно уступает способу массива ... если только не существует какой-то безумной оптимизации, о которой я не знаю.
17
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

Регулярное выражение CraigTP (показано выше) создает некоторые ложные срабатывания. Например. "23y4" будет считаться номером, потому что "." соответствует любому символу, а не десятичной точке.

Также он отклонит любое число с ведущим "+"

Альтернативой, которая позволяет избежать этих двух второстепенных проблем, является

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}
  • 0
    это вернет true для одного плюс "+" или минус "-" , и false для "0."
  • 0
    Хороший улов на один плюс или минус. "0" действительный номер?
Показать ещё 5 комментариев
12

Вы можете использовать NumberFormat#parse:

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}
  • 0
    Предложил редактирование - .getInstance () отсутствует. +1, так как это был ответ, с которым я пошел, когда нашел этот вопрос.
  • 5
    Дорого, если используется экстенсивно
Показать ещё 3 комментария
11

Если вы используете java для разработки приложения для Android, вы можете использовать TextUtils.isDigitsOnly.

9

Вот мой ответ на эту проблему.

Ухватите все удобные методы, которые вы можете использовать для синтаксического анализа любой строки с любым типом анализатора: isParsable(Object parser, String str). Парсер может быть Class или object. Это также позволит использовать пользовательские парсеры, которые вы написали, и должен работать на сценарий, например:

isParsable(Integer.class, "11");
isParsable(Double.class, "11.11");
Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");

Здесь мой код содержит описания методов.

import java.lang.reflect.*;

/**
 * METHOD: isParsable<p><p>
 * 
 * This method will look through the methods of the specified <code>from</code> parameter
 * looking for a public method name starting with "parse" which has only one String
 * parameter.<p>
 * 
 * The <code>parser</code> parameter can be a class or an instantiated object, eg:
 * <code>Integer.class</code> or <code>new Integer(1)</code>. If you use a
 * <code>Class</code> type then only static methods are considered.<p>
 * 
 * When looping through potential methods, it first looks at the <code>Class</code> associated
 * with the <code>parser</code> parameter, then looks through the methods of the parent class
 * followed by subsequent ancestors, using the first method that matches the criteria specified
 * above.<p>
 * 
 * This method will hide any normal parse exceptions, but throws any exceptions due to
 * programmatic errors, eg: NullPointerExceptions, etc. If you specify a <code>parser</code>
 * parameter which has no matching parse methods, a NoSuchMethodException will be thrown
 * embedded within a RuntimeException.<p><p>
 * 
 * Example:<br>
 * <code>isParsable(Boolean.class, "true");<br>
 * isParsable(Integer.class, "11");<br>
 * isParsable(Double.class, "11.11");<br>
 * Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");<br>
 * isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");<br></code>
 * <p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @throws java.lang.NoSuchMethodException If no such method is accessible 
 */
public static boolean isParsable(Object parser, String str) {
    Class theClass = (parser instanceof Class? (Class)parser: parser.getClass());
    boolean staticOnly = (parser == theClass), foundAtLeastOne = false;
    Method[] methods = theClass.getMethods();

    // Loop over methods
    for (int index = 0; index < methods.length; index++) {
        Method method = methods[index];

        // If method starts with parse, is public and has one String parameter.
        // If the parser parameter was a Class, then also ensure the method is static. 
        if(method.getName().startsWith("parse") &&
            (!staticOnly || Modifier.isStatic(method.getModifiers())) &&
            Modifier.isPublic(method.getModifiers()) &&
            method.getGenericParameterTypes().length == 1 &&
            method.getGenericParameterTypes()[0] == String.class)
        {
            try {
                foundAtLeastOne = true;
                method.invoke(parser, str);
                return true; // Successfully parsed without exception
            } catch (Exception exception) {
                // If invoke problem, try a different method
                /*if(!(exception instanceof IllegalArgumentException) &&
                   !(exception instanceof IllegalAccessException) &&
                   !(exception instanceof InvocationTargetException))
                        continue; // Look for other parse methods*/

                // Parse method refuses to parse, look for another different method
                continue; // Look for other parse methods
            }
        }
    }

    // No more accessible parse method could be found.
    if(foundAtLeastOne) return false;
    else throw new RuntimeException(new NoSuchMethodException());
}


/**
 * METHOD: willParse<p><p>
 * 
 * A convienence method which calls the isParseable method, but does not throw any exceptions
 * which could be thrown through programatic errors.<p>
 * 
 * Use of {@link #isParseable(Object, String) isParseable} is recommended for use so programatic
 * errors can be caught in development, unless the value of the <code>parser</code> parameter is
 * unpredictable, or normal programtic exceptions should be ignored.<p>
 * 
 * See {@link #isParseable(Object, String) isParseable} for full description of method
 * usability.<p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @see #isParseable(Object, String) for full description of method usability 
 */
public static boolean willParse(Object parser, String str) {
    try {
        return isParsable(parser, str);
    } catch(Throwable exception) {
        return false;
    }
}
  • 35
    +1 за абсолютный перебор
5

Мы можем попытаться заменить все числа из данной строки на (""), то есть пробел, и если после этого длина строки равна нулю, мы можем сказать, что данная строка содержит только цифры. [Если вы нашли этот ответ полезным, пожалуйста, подумайте над его голосованием] Пример:

boolean isNumber(String str){
       return str.replaceAll("[0-9]","").length() == 0;
}
  • 0
    Значит "" это число, а "3.14" и "-1" нет?
5

Исключения стоят дорого, но в этом случае RegEx занимает гораздо больше времени. В приведенном ниже коде показан простой тест двух функций: один с использованием исключений и один с использованием регулярного выражения. На моей машине версия RegEx в 10 раз медленнее, чем исключение.

import java.util.Date;


public class IsNumeric {

public static boolean isNumericOne(String s) {
    return s.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.      
}

public static boolean isNumericTwo(String s) {
    try {
        Double.parseDouble(s);
        return true;
    } catch (Exception e) {
        return false;
    }
}

public static void main(String [] args) {

    String test = "12345.F";

    long before = new Date().getTime();     
    for(int x=0;x<1000000;++x) {
        //isNumericTwo(test);
        isNumericOne(test);
    }
    long after = new Date().getTime();

    System.out.println(after-before);

}

}
  • 0
    Как правило, я думаю, что этот вид кода будет использоваться для проверки таких вещей, как ввод ввода. В этом случае скорость не учитывается, и делать что-то такое уродливое, как неправильное создание исключения для проверки номера или отсутствия номера.
  • 0
    Возможно, нет. Типизированный ввод обычно проверяется компонентом пользовательского интерфейса, где ошибки могут быть немедленно отображены перед отправкой значения. Может быть более распространено проверять строки из больших входных текстовых файлов - там, где важна производительность. Цель в моем ответе здесь состоит в том, чтобы обратиться к утверждению «исключения являются медленными» в принятом ответе. Сложное регулярное выражение намного дороже. И в моем коде нет никакого «уродливого броска» - просто более быстрый способ выявления нарушений. При использовании метода «сначала проверяй, а потом вычисляй» вы делаете два прохода через вход: один для проверки, а затем для преобразования.
5

Соответствие регулярных выражений

Вот еще один пример обновленного регулярного выражения "CraigTP" с большим количеством проверок.

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  • Только один отрицательный знак - разрешен и должен начинаться.
  • После отрицательного знака должна быть цифра.
  • Разрешен только один десятичный знак ..
  • После десятичного знака должна быть цифра.

Тест регулярных выражений

1                  --                   **VALID**
1.                 --                   INVALID
1..                --                   INVALID
1.1                --                   **VALID**
1.1.1              --                   INVALID

-1                 --                   **VALID**
--1                --                   INVALID
-1.                --                   INVALID
-1.1               --                   **VALID**
-1.1.1             --                   INVALID
5

Вот мой класс для проверки, является ли строка числовой. Он также фиксирует числовые строки:

Особенности:

  • Удаляет ненужные нули [ "12.0000000" → "12" ]
  • Удаляет ненужные нули [ "12.0580000" → "12.058" ]
  • Удаляет нецифровые символы [ "12.00sdfsdf00" → "12" ]
  • Обрабатывает отрицательные строковые значения [ "-12,020000" → "-12.02" ]
  • Удаляет несколько точек [ "-12.0.20.000" → "-12.02" ]
  • Нет дополнительных библиотек, только стандартная Java

Здесь вы идете...

public class NumUtils {
    /**
     * Transforms a string to an integer. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToInteger(String str) {
        String s = str;
        double d;
        d = Double.parseDouble(makeToDouble(s));
        int i = (int) (d + 0.5D);
        String retStr = String.valueOf(i);
        System.out.printf(retStr + "   ");
        return retStr;
    }

    /**
     * Transforms a string to an double. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToDouble(String str) {

        Boolean dotWasFound = false;
        String orgStr = str;
        String retStr;
        int firstDotPos = 0;
        Boolean negative = false;

        //check if str is null
        if(str.length()==0){
            str="0";
        }

        //check if first sign is "-"
        if (str.charAt(0) == '-') {
            negative = true;
        }

        //check if str containg any number or else set the string to '0'
        if (!str.matches(".*\\d+.*")) {
            str = "0";
        }

        //Replace ',' with '.'  (for some european users who use the ',' as decimal separator)
        str = str.replaceAll(",", ".");
        str = str.replaceAll("[^\\d.]", "");

        //Removes the any second dots
        for (int i_char = 0; i_char < str.length(); i_char++) {
            if (str.charAt(i_char) == '.') {
                dotWasFound = true;
                firstDotPos = i_char;
                break;
            }
        }
        if (dotWasFound) {
            String befDot = str.substring(0, firstDotPos + 1);
            String aftDot = str.substring(firstDotPos + 1, str.length());
            aftDot = aftDot.replaceAll("\\.", "");
            str = befDot + aftDot;
        }

        //Removes zeros from the begining
        double uglyMethod = Double.parseDouble(str);
        str = String.valueOf(uglyMethod);

        //Removes the .0
        str = str.replaceAll("([0-9])\\.0+([^0-9]|$)", "$1$2");

        retStr = str;

        if (negative) {
            retStr = "-"+retStr;
        }

        return retStr;

    }

    static boolean isNumeric(String str) {
        try {
            double d = Double.parseDouble(str);
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }

}
5

Чтобы соответствовать только положительным целым числам base-ten, содержащим только цифры ASCII, используйте:

public static boolean isNumeric(String maybeNumeric) {
    return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}
5

Хорошо выполняющий подход, избегающий попытки захвата и обработки отрицательных чисел и научной нотации.

Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );

public static boolean isNumeric( String value ) 
{
    return value != null && PATTERN.matcher( value ).matches();
}
4

//см. ниже код

public static boolean isDigitsOnly(CharSequence str) {
    final int len = str.length();
    for (int i = 0; i < len; i++) {
        if (!Character.isDigit(str.charAt(i))) {
            return false;
        }
    }
    return true;
}
  • 0
    Вопрос говорит «числовой», который может включать нецелые значения.
3

Вы можете использовать объект java.util.Scanner.

public static boolean isNumeric(String inputData) {
      Scanner sc = new Scanner(inputData);
      return sc.hasNextInt();
    }
3

Это простой пример этой проверки:

public static boolean isNumericString(String input) {
    boolean result = false;

    if(input != null && input.length() > 0) {
        char[] charArray = input.toCharArray();

        for(char c : charArray) {
            if(c >= '0' && c <= '9') {
                // it is a digit
                result = true;
            } else {
                result = false;
                break;
            }
        }
    }

    return result;
}
3
// only int
public static boolean isNumber(int num) 
{
    return (num >= 48 && c <= 57); // 0 - 9
}

// is type of number including . - e E 
public static boolean isNumber(String s) 
{
    boolean isNumber = true;
    for(int i = 0; i < s.length() && isNumber; i++) 
    {
        char c = s.charAt(i);
        isNumber = isNumber & (
            (c >= '0' && c <= '9') || (c == '.') || (c == 'e') || (c == 'E') || (c == '')
        );
    }
    return isInteger;
}

// is type of number 
public static boolean isInteger(String s) 
{
    boolean isInteger = true;
    for(int i = 0; i < s.length() && isInteger; i++) 
    {
        char c = s.charAt(i);
        isInteger = isInteger & ((c >= '0' && c <= '9'));
    }
    return isInteger;
}

public static boolean isNumeric(String s) 
{
    try
    {
        Double.parseDouble(s);
        return true;
    }
    catch (Exception e) 
    {
        return false;
    }
}
2

Если вы, ребята, используете следующий метод для проверки:

public static boolean isNumeric(String str) {
    NumberFormat formatter = NumberFormat.getInstance();
    ParsePosition pos = new ParsePosition(0);
    formatter.parse(str, pos);
    return str.length() == pos.getIndex();
}

Тогда что происходит с вводом очень длинной строки, такой как я называю этот метод:

System.out.println(isNumeric("94328948243242352525243242524243425452342343948923"));

Результат - "правда", и это слишком большое число! То же самое произойдет, если вы используете регулярное выражение для проверки! Поэтому я бы предпочел использовать метод "разбора" для проверки, например так:

public static boolean isNumeric(String str) {
    try {
        int number = Integer.parseInt(str);
        return true;
    } catch (Exception e) {
        return false;
    }
}

И результат - то, что я ожидал!

  • 0
    «это число слишком большого размера» → «числа слишком большого размера» не существует. Числа бесконечны. 7645 - это число, а 92847294729492875982452012471041141990140811894142729051 - это тоже число. Первый может быть представлен как Integer а второй может быть представлен как BigDecimal . И даже если они не могут быть представлены в Java как объект, они все равно являются числами - вот что задает вопрос.
  • 0
    Кроме того, не злоупотребляйте исключениями. Ява не питон. По крайней мере, используйте более конкретное NumberFormatException
2

Вы можете использовать NumberUtils.isCreatable() из Apache Commons Lang.

Так как NumberUtils.isNumber будет устаревшим в 4.0, поэтому вместо этого используйте NumberUtils.isCreatable().

2

Вот почему мне нравится подход Try * в .NET. В дополнение к традиционному методу Parse, подобному Java, у вас также есть метод TryParse. Я не очень хорошо разбираюсь в синтаксисе Java (out parameters?), Поэтому, пожалуйста, рассматривайте следующее как своего рода псевдокод. Это должно сделать концепцию понятной, хотя.

boolean parseInteger(String s, out int number)
{
    try {
        number = Integer.parseInt(myString);
        return true;
    } catch(NumberFormatException e) {
        return false;
    }
}

Использование:

int num;
if (parseInteger("23", out num)) {
    // Do something with num.
}
  • 0
    да, в Java нет «параметров out», и поскольку обертка Integer является неизменяемой (поэтому ее нельзя использовать в качестве допустимой ссылки для хранения вывода), разумной идиоматической опцией будет возвращение объекта Integer, который может быть нулевым, если анализ выполняется не удалось. Более уродливым вариантом может быть передача int [1] в качестве выходного параметра.
  • 0
    Да, я помню обсуждение того, почему у Java нет выходных параметров. но возвращать Integer (как ноль, если необходимо) тоже было бы неплохо, я думаю, хотя я не знаю о производительности Java в отношении упаковки / распаковки.
Показать ещё 2 комментария
2

Разберите его (т.е. Integer#parseInt) и просто поймайте исключение. =)

Чтобы уточнить: функция parseInt проверяет, может ли он разбирать номер в любом случае (очевидно), и если вы все равно его анализируете, вы не будете получать какой-либо удар производительности, фактически выполняя разбор.

Если вы не хотите анализировать его (или разбирать его очень, очень редко), вы можете сделать это по-разному, конечно.

  • 1
    Дорого, если используется экстенсивно
  • 0
    Это создаст проблему сонара, если вы не регистрируете исключение
Показать ещё 1 комментарий
1

Параллельная проверка очень длинных строк с использованием IntStream

В Java 8 следующие тесты, если все символы данной string находятся в пределах от "0" до "9". Имейте в виду, что пустая строка принимается:

string.chars().unordered().parallel().allMatch( i -> '0' <= i && '9' >= i )
1

Это самый быстрый способ узнать, является ли String Number или нет:

public static boolean isNumber(String str){
  int i=0, len=str.length();
  boolean a=false,b=false,c=false, d=false;
  if(i<len && (str.charAt(i)=='+' || str.charAt(i)=='-')) i++;
  while( i<len && isDigit(str.charAt(i)) ){ i++; a=true; }
  if(i<len && (str.charAt(i)=='.')) i++;
  while( i<len && isDigit(str.charAt(i)) ){ i++; b=true; }
  if(i<len && (str.charAt(i)=='e' || str.charAt(i)=='E') && (a || b)){ i++; c=true; }
  if(i<len && (str.charAt(i)=='+' || str.charAt(i)=='-') && c) i++;
  while( i<len && isDigit(str.charAt(i)) ){ i++; d=true;}
  return i==len && (a||b) && (!c || (c && d));
}
static boolean isDigit(char c){
  return c=='0' || c=='1' || c=='2' || c=='3' || c=='4' || c=='5' || c=='6' || c=='7' || c=='8' || c=='9';
}
1

Я модифицировал решение CraigTP, чтобы принять научную нотацию и как точку, так и запятую как десятичные разделители, а также

^-?\d+([,\.]\d+)?([eE]-?\d+)?$

Пример

var re = new RegExp("^-?\d+([,\.]\d+)?([eE]-?\d+)?$");
re.test("-6546"); // true
re.test("-6546355e-4456"); // true
re.test("-6546.355e-4456"); // true, though debatable
re.test("-6546.35.5e-4456"); // false
re.test("-6546.35.5e-4456.6"); // false
1

Вот два метода, которые могут работать. (Без использования исключений). Примечание. Java по умолчанию является пошаговой, а значение String является адресом данных объекта String. Итак, когда вы делаете

stringNumber = stringNumber.replaceAll(" ", "");

Вы изменили входное значение, чтобы не было пробелов. Вы можете удалить эту строку, если хотите.

private boolean isValidStringNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if(!Character.isDigit(charNumber[i]))
        {
            return false;
        }
    }
    return true;
}

Вот еще один метод, если вы хотите разрешить поплавки Этот метод якобы позволяет номерам в форме пройти 1,123,123,123,123,123.123 Я только что сделал это, и я думаю, что ему нужно дополнительное тестирование, чтобы убедиться, что оно работает.

private boolean isValidStringTrueNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");
    int countOfDecimalPoint = 0;
    boolean decimalPointPassed = false;
    boolean commaFound = false;
    int countOfDigitsBeforeDecimalPoint = 0;
    int countOfDigitsAfterDecimalPoint =0 ;
    int commaCounter=0;
    int countOfDigitsBeforeFirstComma = 0;

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if((commaCounter>3)||(commaCounter<0))
        {
            return false;
        }
        if(!Character.isDigit(charNumber[i]))//Char is not a digit.
        {
            if(charNumber[i]==',')
            {
                if(decimalPointPassed)
                {
                    return false;
                }
                commaFound = true;
                //check that next three chars are only digits.
                commaCounter +=3;
            }
            else if(charNumber[i]=='.')
            {
                decimalPointPassed = true;
                countOfDecimalPoint++;
            }
            else
            {
                return false;
            }
        }
        else //Char is a digit.
        {
            if ((commaCounter>=0)&&(commaFound))
            {
                if(!decimalPointPassed)
                {
                    commaCounter--;
                }
            }

            if(!commaFound)
            {
                countOfDigitsBeforeFirstComma++;
            }

            if(!decimalPointPassed)
            {
                countOfDigitsBeforeDecimalPoint++;
            }
            else
            {
                countOfDigitsAfterDecimalPoint++;
            }
        }
    }
    if((commaFound)&&(countOfDigitsBeforeFirstComma>3))
    {
        return false;
    }
    if(countOfDecimalPoint>1)
    {
        return false;
    }

    if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0)))
    {
        return false;
    }
    return true;
}
  • 0
    Что если число содержит запятые или десятичные точки?
  • 0
    О, хороший вопрос. Я думаю, что это работает только нормальные целые числа типа. Метод изначально был создан для фильтрации входных телефонных номеров и подсчета номеров.
1

Вы можете использовать BigDecimal, если строка может содержать десятичные знаки:

try {
    new java.math.BigInteger(testString);
} catch(NumberFormatException e) {
    throw new RuntimeException("Not a valid number");
}
  • 6
    Добро пожаловать в stackoverflow. Как правило, лучше избегать воскрешения старых потоков, если в ответе не добавлено что-то значительно отличающееся от потока. Хотя этот подход действителен, он уже упоминался в принятом ответе.
  • 0
    Это создаст проблему сонара, если вы не регистрируете исключение
0

Основываясь на других ответах, я написал свой, и он не использует шаблоны или синтаксический анализ с проверкой исключений.

Он проверяет максимум один знак минус и проверяет максимум один десятичный знак.

Вот несколько примеров и их результаты:

"1", "-1", "-1.5" и "-1.556" возвращают true

"1..5", "1A.5", "1.5D", "-" и "- -1" возвращают false

Примечание. При необходимости вы можете изменить это так, чтобы он принимал параметр Locale и передавал его в вызовы DecimalFormatSymbols.getInstance(), чтобы использовать конкретный Locale вместо текущего.

 public static boolean isNumeric(final String input) {
    //Check for null or blank string
    if(input == null || input.isBlank()) return false;

    //Retrieve the minus sign and decimal separator characters from the current Locale
    final var localeMinusSign = DecimalFormatSymbols.getInstance().getMinusSign();
    final var localeDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();

    //Check if first character is a minus sign
    final var isNegative = input.charAt(0) == localeMinusSign;
    //Check if string is not just a minus sign
    if (isNegative && input.length() == 1) return false;

    var isDecimalSeparatorFound = false;

    //If the string has a minus sign ignore the first character
    final var startCharIndex = isNegative ? 1 : 0;

    //Check if each character is a number or a decimal separator
    //and make sure string only has a maximum of one decimal separator
    for (var i = startCharIndex; i < input.length(); i++) {
        if(!Character.isDigit(input.charAt(i))) {
            if(input.charAt(i) == localeDecimalSeparator && !isDecimalSeparatorFound) {
                isDecimalSeparatorFound = true;
            } else return false;
        }
    }
    return true;
}
0

Я проиллюстрировал некоторые условия для проверки чисел и десятичных знаков без использования какого-либо API,

Проверить размер исправления 1-значный номер

Character.isDigit(char)

Проверьте размер длины исправления (предположим, длина 6)

String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");

Проверьте размер переменной количества (от 4 до 6)

//  {n,m}  n <= length <= m
String number = "132452";
if(number.matches("([0-9]{4,6})"))
System.out.println("Number Identified between 4 to 6 length");

String number = "132";
if(!number.matches("([0-9]{4,6})"))
System.out.println("Number not in length range or different format");

Проверьте размер переменной десятичного числа между (предположим, длина от 4 до 7)

//  It will not count the '.' (Period) in length
String decimal = "132.45";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1.12";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1234";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "-10.123";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "123..4";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "132";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "1.1";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

Надеюсь, это поможет многим.

0

Java 8 Stream, лямбда-выражение, функциональный интерфейс

Все обработанные случаи (строка null, строка пустая и т.д.)

String someString = null; // something="", something="123abc", something="123123"

boolean isNumeric = Stream.of(someString)
            .filter(s -> s != null && !s.isEmpty())
            .filter(Pattern.compile("\\D").asPredicate().negate())
            .mapToLong(Long::valueOf)
            .boxed()
            .findAny()
            .isPresent();
0
String text="hello 123";
if(Pattern.matches([0-9]+))==true
System.out.println("String"+text);
0

Попробуйте следующее:

public  boolean isNumber(String str)
{       
    short count = 0;
    char chc[]  = {'0','1','2','3','4','5','6','7','8','9','.','-','+'};
    for (char c : str.toCharArray())
    {   
        for (int i = 0;i < chc.length;i++)
        {
            if( c  == chc[i]){
                count++;        
            }
         }                      
    }
    if (count != str.length() ) 
        return false;
    else
        return true;
}
  • 2
    Это вернет истину, если вы передадите "++++" ...
0

Если вы хотите выполнить проверку с помощью регулярного выражения, вы должны создать конечный объект статического шаблона, так что регулярное выражение нужно будет только компилировать. Компиляция регулярного выражения занимает примерно столько же времени, сколько выполняется, поэтому, приняв эту меру предосторожности, вы сократите время выполнения метода наполовину.

final static Pattern NUMBER_PATTERN = Pattern.compile("[+-]?\\d*\\.?\\d+");

static boolean isNumber(String input) {
    Matcher m = NUMBER_PATTERN.matcher(input);
    return m.matches();
}

Я предполагаю, что число - это строка, в которой нет ничего, кроме десятичных цифр, возможно знак + или - в начале и не более одной десятичной точки (а не в конце) и других символов (включая запятые, пробелы, числа в других системах подсчета, римские цифры, иероглифы).

Это решение является кратким и довольно быстрым, но вы можете сбрить пару миллисекунд за миллион вызовов, сделав это так

static boolean isNumber(String s) {
    final int len = s.length();
    if (len == 0) {
        return false;
    }
    int dotCount = 0;
    for (int i = 0; i < len; i++) {
        char c = s.charAt(i);
        if (c < '0' || c > '9') {
            if (i == len - 1) {//last character must be digit
                return false;
            } else if (c == '.') {
                if (++dotCount > 1) {
                    return false;
                }
            } else if (i != 0 || c != '+' && c != '-') {//+ or - allowed at start
                return false;
            }

        }
    }
    return true;
}
0

Я думаю, что единственный способ достоверно определить, является ли строка числом, - это проанализировать ее. Поэтому я просто проанализирую его, и если это число, вы получите номер в int бесплатно!

-2
import java.util.Scanner;

public class TestDemo {
    public static void main(String[] args) {
        boolean flag = true;
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter the String:");
        String str = sc.nextLine();

        for (int i = 0; i < str.length(); i++) {
            if(str.charAt(i) > 48 && str.charAt(i) < 58) {
                flag = false;
                break;
            }
        }

        if(flag == true) {
            System.out.println("String is a valid String.");
        } else {
            System.out.println("String contains number.");
        }
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню