Вопрос по string, numeric, java – Как проверить, является ли строка числовой в Java

775

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

Нулевые строки @HiteshSahu, кажется, изящно обрабатываются в последней версии (включая Java 6.x и 7.x) lifebalance
См. Ответ Макса Малыша для краткого решения Java 8 без сторонних библиотек. Andy Thomas
Все решения, предложенные для использованияInteger.parseInt() не сможет разобрать мобильные номера сNumberFormatException. Not a bug
Все решения, предлагаемые с регулярными выражениями, не будут работать для шестнадцатеричных чисел. Oscar Castiblanco
и передача пустой строки в функции match (...) вызовет исключение NullPointer. Hitesh Sahu

Ваш Ответ

30   ответов
20

Why is everyone pushing for exception/regex solutions?

Хотя я понимаю, что большинству людей хорошо использовать 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

Disclaimer: I'm not claiming these methods are 100% optimized, they're just for demonstration of the data

Исключения выигрывают, если и только если число составляет 4 символа или менее, и каждая строкаalways номер ... в таком случае, зачем вообще чек?

Короче говоря, это очень больно, если вы часто сталкиваетесь с недопустимыми числами с помощью try / catch, что имеет смысл. Важное правило, которому я всегда следуюNEVER use try/catch for program flow, Это пример почему.

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

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

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

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 +) всегда показывал, что он медленнее.

РЕДАКТИРОВАТЬ: Обновлен тест для Character.isDigit ()

Разве это не компилирует новое регулярное выражение каждый раз? Это не кажется очень эффективным.
@SamuelEdwinWard Этоwhole причина, по которой я сделал этот пост ... пример регулярного выражения использовал ответы других людей и показал, насколько он неэффективен. Даже если вы попытаетесь выполнить регулярное выражение с предварительной компиляцией заранее и только с его использованием, разница во времени составит: 2587 мс для регулярного выражения, которое я отправил от других пользователей, 950 мс при предварительной компиляции, 144 мс при выполнении этого как числовой массив (для 1 млн итераций одной и той же строки). Компиляция заблаговременно, очевидно, помогла бы, но, к сожалению, она все еще значительно уступает способу массива ... если только не существует какой-то безумной оптимизации, о которой я не знаю.
12

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

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}
Это работало для числового формата 0x0001, где Double.parseDouble не работал. +1
Это создаст проблему сонара, если вы не зарегистрируете исключение
Дорого, если используется экстенсивно
Предложил редактирование - .getInstance () отсутствует. +1, так как это был ответ, с которым я пошел, когда нашел этот вопрос.
Это также пройдет, если в концеvalue.
5

Regex Matching

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

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
Only one negative sign - allowed and must be in beginning. After negative sign there must be digit. Only one decimal sign . allowed. After decimal sign there must be digit.

Regex Test

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
2

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

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.
}
Это создаст проблему сонара, если вы не зарегистрируете исключение
да, "нет" выходных параметров " в Java и поскольку обертка Integer является неизменяемой (поэтому ее нельзя использовать в качестве допустимой ссылки для хранения выходных данных), разумной идиоматической опцией будет возвращение объекта Integer, который может иметь значение null в случае сбоя анализа. Более уродливым вариантом может быть передача int [1] в качестве выходного параметра.
Мне нравится C # так же, как и следующему парню, но бесполезно добавлять фрагмент кода .NET C # для вопроса Java, когда функции не существуют в Java
Да, я помню обсуждение того, почему у Java нет выходных параметров. но возвращать Integer (как ноль, если необходимо) тоже было бы хорошо, я думаю, хотя я не знаю о производительности Java в отношении упаковки / распаковки.
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);

}

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

Apache Commons Lang.

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

2

Integer#parseInt ) и просто поймать исключение. знак равно

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

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

Double.parseDouble
Дорого, если используется экстенсивно
Это создаст проблему сонара, если вы не зарегистрируете исключение
8

Удобный метод перехвата, который вы можете использовать для анализа любой строки с любым типом парсера: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's 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;
    }
}
+1 за абсолютный перебор
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;
    }
}
1

Это самый быстрый способ, которым я знаю, чтобы проверить, является ли строка числовой или нет:

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';
}
833

это делается с помощью простой пользовательской функции (то есть, функция Roll-your-own & quot; isNumeric & quot;).

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

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

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

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

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

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

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

public static boolean isNumeric(String str) {
  NumberFormat formatter = NumberFormat.getInstance();
  ParsePosition pos = new ParsePosition(0);
  formatter.parse(str, pos);
  return str.length() == pos.getIndex();
}
\ D в Java Regex соответствует только латинским цифрам? Если это похоже на регулярные выражения .NET, вы столкнетесь с проблемой с другими (например, арабскими) цифрами, как объяснено здесь:blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
Обратите внимание, что. в вашем регулярном выражении будет соответствовать любой символ, а не только символ десятичного разделителя.
+1 для реализации за счет попробовать / поймать. Это на самом деле ужасный подход для использования в долгосрочной перспективе для повторного использования, но на самом деле мы застряли с этим в Java.
Следует отметить, что нет таких вещей, как «латинские цифры», и цифры 0-9 фактически являются арабскими цифрами. Люди, вероятно, знакомы с римскими цифрами, которые использовались людьми, которые говорили на латыни, в форме I, II, III, IV, V, VI и т. Д.en.wikipedia.org/wiki/Arabic_numerals; en.wikipedia.org/wiki/Roman_numerals
Решение numberFormatter, вероятно, лишь незначительно лучше, чем улавливание NumberFormatException. Я подозреваю, что лучший способ - это использовать регулярные выражения.
5

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

Features:

  1. Removes unnecessary zeros ["12.0000000" -> "12"]
  2. Removes unnecessary zeros ["12.0580000" -> "12.058"]
  3. Removes non numerical characters ["12.00sdfsdf00" -> "12"]
  4. Handles negative string values ["-12,020000" -> "-12.02"]
  5. Removes multiple dots ["-12.0.20.000" -> "-12.02"]
  6. No extra libraries, just standard 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;
    }

}
11

вы можете использоватьTextUtils.isDigitsOnly функция.

3

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

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

я этого: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 выше. В их реализации нет накладных расходов на обработку исключений.

1

Java 8 Stream, lambda expression, functional interface

Все дела обработаны (string null, string empty etc)

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();
139

Если вы на Android, то вы должны использовать:

android.text.TextUtils.isDigitsOnly(CharSequence str)

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

keep it simple, в основном каждый может «перепрограммировать» (тоже самое).

Это не будет работать для 123.456; (
Примечание: это приводит к NPE для нулевого ввода. Кроме того, не работает с отрицательными числами или десятичными числами.
@ kape123 :) Обязательно & quot; 123.456 & quot; не содержит цифр.
Мне это нравится!! Я думаю, что это абсолютно для цифр. Не для., -
Это именно то, что я искал. Что-то простое, чтобы проверить только цифры 0-9. Я установил фильтр в объявлении моего EditText, но на случай, если он будет изменен или заменен в будущем, было бы хорошо иметь простую программную проверку.
115

у меня также есть похожие проблемы с производительностью при использовании Исключений для проверки, является ли строка числовой или нет. Так что я в конечном итоге разбить строку и использовать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 - количество символов в строке, было бы более вычислительно эффективным, чем сопоставление с регулярным выражением.

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

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;
}
@ Jean-Fran & # xE7; oisCorbett: Хорошо, я обновил код более новым, который принимает десятичные разделители.
Я думаю, что это должен быть принятый ответ, потому что это самое легкое решение. Использование исключения или регулярного выражения очень сложно проверить, является ли строка числовой. Перебирая персонажей, это приятно и просто!
Не является ли десятичный разделитель причиной сбоя?
Знак -ve не справляется с этой функцией?
Приведенный выше код принимает один «-» как числовое и вернет true. изменить первымif что-то вроде:boolean isMinus = str.charAt(0) == localeMinusSign; if ((isMinus && str.length() < 2) || ((!isMinus) && !Character.isDigit(str.charAt(0)))) { return false; }
2

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

^-?\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;
}

Here is another method in case you want to allow floats This method allegedly allows numbers in the form to pass 1,123,123,123,123,123.123 i have just made it , and i think it needs further testing to ensure it is working.

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 dig,it.
        {
            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;
}
Что если число содержит запятые или десятичные точки?
О, хороший вопрос. Я думаю, что это работает только целые числа нормального типа. Метод изначально был создан для фильтрации входных телефонных номеров и подсчета номеров.
18
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

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

Также он будет отклонять любое число с начальным «+»;

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

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}
Хороший улов на один плюс или минус. Is & quot; 0. & quot; действительный номер?
Создание регулярных выражений также является дорогостоящим. Регулярное выражение должно быть создано один раз и использовано повторно
"0." действует дляDouble.parseDouble() и является действительным литералом в соответствии с JLS (§3.10.2)!
это вернетсяtrue за один плюс"+" или минус"-", а такжеfalse for "0."
Ответ не полный."21a12".matches("-?\\d+(.\\d+)?") возвращает истину !!!
1

BigDecimal если строка может содержать десятичные дроби:

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

Do not use Exceptions to validate your values. Вместо этого используйте Util libs, как apache NumberUtils:

NumberUtils.isNumber(myStringValue);

Edit:

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

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
Я так не думаю. Он был обновлен или оп изменил принятый ответ. Я помню, что принятый ответ не охватывал NumberUtils, поэтому я добавил свой ответ. Но спасибо за комментарий
@ Goot, это очень хорошо, так как в отличие от StringUtils, оно также включает проверку десятичного значения.
Принятый ответ, тремя годами ранее, уже освещенNumber.isNumber().
@ Goot - история принятого ответа показывает, чтоNumber.isNumber() присутствовал в первом варианте ответа, датированном 24 сентября 12, в 17:01.
81

Java 8 лямбда-выражений.

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
Этот ответ является кратким, простым и читабельным. Вы можете почти прочитать это как английский - & quot; символы все совпадают с цифрами & quot ;. Не требует сторонних библиотек. Он не использует исключения в неисключительных случаях. Это должно стать принятым ответом.
Вы также можете использовать ссылку на метод: someString.chars (). AllMatch (Character :: isDigit)
Хорошо, но все же он изобретает велосипед как почти все "решения". Вот. Кроме того, происходит сбой при 'null' (как и почти все остальные).
@ Адриан вот эталон:gist.github.com/maxmalysh/8f656be2843b7c35849a2eae2683df0e , 9 мс для строки длиной 1 миллион символов. 169 мс для строки длиной 5 Кб это что-то слишком необычное.
Что он будет производить для & quot; -1 & quot ;?
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();
}
10

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

boolean isNumber(String str){
       return str.replaceAll("[0-9]","").length() == 0;
}
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;
}
5

исел, которые содержат только цифры ASCII, используйте:

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

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

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

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

заново изобретать колесо, потому что вы не включаете целую библиотеку, потому что вам нужна трехстрочная функция в одном месте.
Не работает с негативами. И половина всех чисел отрицательна, так что .....
Это действительно стоит добавитьwhole библиотека для этой функции, хотя? Очевидно, что если он используется с другими вещами, что замечательно, но это, вероятно, излишне, учитывая, что люди решили это в одной строке кода.
+1 Зачем заново изобретать колесо.
StringUtils.isNumeric() вероятно, здесь не будет уместно, поскольку он только проверяет, является ли строка последовательностью цифр. Подойдет для большинства целых, но не для чисел с десятичными числами, разделителями групп и т. Д.
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;
}
Вопрос гласит «числовой» который может включать нецелые значения.

Похожие вопросы