Java String - Проверьте, содержит ли строка только цифры, а не буквы


197

У меня есть строка, которую я загружаю по всему приложению, и она меняется с цифр на буквы и тому подобное. У меня есть простое ifутверждение, чтобы увидеть, содержит ли оно буквы или цифры, но что-то работает не совсем правильно. Вот фрагмент.

String text = "abc"; 
String number; 

if (text.contains("[a-zA-Z]+") == false && text.length() > 2) {
    number = text; 
}

Хотя textпеременная содержит буквы, условие возвращается как true. И &&должны быть оценены как оба условия должны быть trueдля обработкиnumber = text;

==============================

Решение:

Я смог решить эту проблему с помощью следующего кода, предоставленного комментарием по этому вопросу. Все остальные посты также действительны!

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

String text = "abc"; 
String number; 

if (Pattern.matches("[a-zA-Z]+", text) == false && text.length() > 2) {
    number = text; 
}

5
Содержит не принимает регулярное выражение в качестве входных данных. Используйте matches("\\d{2,}")или попробуйте с PatternиMatcher
Гийом Полет

Может ли строка иметь десятичное значение или только целочисленные значения?
псевдорабль

3
Почему вы проверяете text.length ()> 2? В чем причина?
Код энтузиазма

1
@RedHatcc Pattern.matches("[a-zA-Z]+", text) == falseможно упростить до!Pattern.matches("[a-zA-Z]+", text)
SARose

2
Использование Java потокового API boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));форму Max MalyshPost.
Яш

Ответы:


356

Если вы будете обрабатывать число как текст, измените:

if (text.contains("[a-zA-Z]+") == false && text.length() > 2){

чтобы:

if (text.matches("[0-9]+") && text.length() > 2) {

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

Если вы действительно хотите использовать числовое значение, используйте Integer.parseInt()или, Double.parseDouble()как другие объяснили ниже.


Как примечание, обычно считается плохой практикой сравнивать логические значения с trueили false. Просто используйте if (condition)или if (!condition).


25
Вы, вероятно, хотите добавить якоря (например ^[0-9]+$), иначе abc123defбудет считаться число.
ICR

10
Я не думаю, что это требуется. matches()возвращает true тогда и только тогда, когда это полное совпадение от начала до конца.
Хтонический проект

4
«^ -? \ d + \.? \ d * $» будет сравнивать всю строку и совпадать только в том случае, если это допустимое число (включая минус и десятичные дроби). Например, он будет соответствовать 1, 10, 1.0, -1, -1.0 и т. Д. Он также будет соответствовать «1». но это часто можно проанализировать в любом случае.

16
Нет необходимости звонить && (text.length() > 2). Все можно проверить в регулярном выражении:if (text.matches("[0-9]{3,}")
ctomek

Как насчет запятых или точек для чисел, которые не являются целыми числами?
Ниббана

20

Вы также можете использовать NumberUtil.isCreatable (String str) из Apache Commons.


4
Я не думаю, что NumberUtil.isCreatable(String str)правильно использовать для того, что просит оригинальный вопрос. Например, NumberUtil.isCreatable( "09" )возвращается false, хотя "09" содержит только цифры .
Абдул

14

Вот как я бы это сделал:

if(text.matches("^[0-9]*$") && text.length() > 2){
    //...
}

$Позволит избежать частичного совпадения , например; 1B,


1
Мне не нужна эта text.length() > 2часть, поэтому я просто заменил ^[0-9]*$ее, ^[0-9]+$чтобы убедиться, что у меня есть хотя бы один номер.
YB Причина

8

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

Я запустил тесты jmh и обнаружил, что перебор String с использованием charAtи сравнение символов с граничными символами - это самый быстрый способ проверить, содержит ли строка только цифры.

JMH тестирование

Тесты сравнение производительности Character.isDigitпротив Pattern.matcher().matchesпротив Long.parseLongпротив проверки значений полукокса.

Эти способы могут привести к разным результатам для строк, отличных от ascii, и строк, содержащих знаки +/-.

Тесты выполняются в режиме пропускной способности (чем больше, тем лучше ) с 5 итерациями прогрева и 5 итерациями теста.

Полученные результаты

Обратите внимание, что parseLongэто почти в 100 раз медленнее, чем isDigitпри первой тестовой нагрузке.

## Test load with 25% valid strings (75% strings contain non-digit symbols)

Benchmark       Mode  Cnt  Score   Error  Units
testIsDigit    thrpt    5  9.275 ± 2.348  ops/s
testPattern    thrpt    5  2.135 ± 0.697  ops/s
testParseLong  thrpt    5  0.166 ± 0.021  ops/s

## Test load with 50% valid strings (50% strings contain non-digit symbols)

Benchmark              Mode  Cnt  Score   Error  Units
testCharBetween       thrpt    5  16.773 ± 0.401  ops/s
testCharAtIsDigit     thrpt    5  8.917 ± 0.767  ops/s
testCharArrayIsDigit  thrpt    5  6.553 ± 0.425  ops/s
testPattern           thrpt    5  1.287 ± 0.057  ops/s
testIntStreamCodes    thrpt    5  0.966 ± 0.051  ops/s
testParseLong         thrpt    5  0.174 ± 0.013  ops/s
testParseInt          thrpt    5  0.078 ± 0.001  ops/s

Тестирование

@State(Scope.Benchmark)
public class StringIsNumberBenchmark {
    private static final long CYCLES = 1_000_000L;
    private static final String[] STRINGS = {"12345678901","98765432177","58745896328","35741596328", "123456789a1", "1a345678901", "1234567890 "};
    private static final Pattern PATTERN = Pattern.compile("\\d+");

    @Benchmark
    public void testPattern() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = PATTERN.matcher(s).matches();
            }
        }
    }

    @Benchmark
    public void testParseLong() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                try {
                    Long.parseLong(s);
                    b = true;
                } catch (NumberFormatException e) {
                    // no-op
                }
            }
        }
    }

    @Benchmark
    public void testCharArrayIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (char c : s.toCharArray()) {
                    b = Character.isDigit(c);
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testCharAtIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    b = Character.isDigit(s.charAt(j));
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testIntStreamCodes() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = s.chars().allMatch(c -> c > 47 && c < 58);
            }
        }
    }

    @Benchmark
    public void testCharBetween() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    char charr = s.charAt(j);
                    b = '0' <= charr && charr <= '9';
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }
}

Обновлено 23 февраля 2018 г.

  • Добавьте еще два случая - одно использование charAtвместо создания дополнительного массива и другое использование IntStreamкодов символов
  • Добавьте немедленный разрыв, если для зацикленных тестовых случаев найдена нецифровка
  • Вернуть false для пустой строки для циклических тестов

Обновлено 23 февраля 2018 г.

  • Добавьте еще один тестовый пример (самый быстрый!), Который сравнивает значение char без использования stream

1
Если вы посмотрите на код toCharArray, он выделяет массив символов и копирует символы (я думаю, это может быть дорого). А что если вы просто итерируете строку, используя index и charAt, это будет быстрее? Было бы интересно также , если вы могли бы добавить решение от Энди ваших тестов:. Булево isNum = text.chars () allMatch (с -> с> = 48 && с <= 57)
Альдо Canepa

8

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

if (text.matches("[a-zA-Z]+"){
   // your operations
}

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

if (text.matches("[0-9]+"){
   // your operations
}

Надеюсь, это кому-нибудь поможет!


3

логическое isNum = text.chars (). allMatch (c -> c> = 48 && c <= 57)


1
чтобы уменьшить магические числа, вы можете сравнить их следующим образом:boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
Phe0nix

2

Вы можете использовать Regex.Match

if(text.matches("\\d*")&& text.length() > 2){
    System.out.println("number");
}

Или вы можете использовать инверсии вроде Integer.parseInt(String)или лучше Long.parseLong(String)для больших чисел, например:

private boolean onlyContainsNumbers(String text) {
    try {
        Long.parseLong(text);
        return true;
    } catch (NumberFormatException ex) {
        return false;
    }
} 

А затем проверьте с помощью:

if (onlyContainsNumbers(text) && text.length() > 2) {
    // do Stuff
}

.matches ("^ \\ d + $")
CrandellWS

2

Ниже приведены регулярные выражения, чтобы проверить, имеет ли строка только номер или нет:

if (str.matches(".*[^0-9].*")) or if (str.matches(".*\\D.*"))

Оба условия выше вернутся, trueесли строка содержит не числа. В falseстроке есть только цифры.


2

Предоставляет Apache Commons Langorg.apache.commons.lang.StringUtils.isNumeric(CharSequence cs) , который принимает в качестве аргумента a Stringи проверяет, состоит ли он из чисто цифровых символов (включая числа из нелатинских алфавитов). Этот метод возвращает, falseесли есть символы, такие как пробел, минус, плюс, и десятичные разделители, такие как запятая и точка.

Другие методы этого класса допускают дальнейшие числовые проверки.


1
Это должно быть намного быстрее, чем регулярное выражение; Вот реализация: public static boolean isNumeric(String str) { if (str == null) { return false; } else { int sz = str.length(); for(int i = 0; i < sz; ++i) { if (!Character.isDigit(str.charAt(i))) { return false; } } return true; } }
Лев

1

Существует множество возможностей для получения чисел из Strings в Java (и наоборот). Вы можете пропустить часть регулярных выражений, чтобы избавить себя от осложнений этого.

Например, вы можете попробовать и посмотреть, что Double.parseDouble(String s)для вас возвращается. Он должен бросить a, NumberFormatExceptionесли не находит подходящего значения в строке. Я бы предложил этот метод, потому что вы могли бы использовать значение, представленное Stringкак числовой тип.


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

1
@OfirLuzon Я согласен, что исключения не являются отличным способом обработки ожидаемых случаев, которые могут возникнуть. Однако я думаю, что трудно сказать, будет ли снижение производительности без дополнительного контекста.
псевдорабел

1

Вот мой код, надеюсь, это поможет вам!

 public boolean isDigitOnly(String text){

    boolean isDigit = false;

    if (text.matches("[0-9]+") && text.length() > 2) {
        isDigit = true;
    }else {
        isDigit = false;
    }

    return isDigit;
}

0

Этот код уже написан. Если вы не возражаете против (чрезвычайно) незначительного снижения производительности - что, вероятно, не хуже, чем сопоставление с регулярным выражением - используйте Integer.parseInt () или Double.parseDouble () . Это вам скажу сразу , если строка только цифры (или это число, в зависимости от обстоятельств). Если вам нужно обрабатывать более длинные строки чисел, оба спортивных конструктора BigInteger и BigDecimal, которые принимают строки. Любое из них вызовет исключение NumberFormatException, если вы попытаетесь передать ему не число (целое или десятичное, конечно, на основе того, которое вы выберете). Кроме того, в зависимости от ваших требований, просто переберите символы в строке и проверьте Character.isDigit ()и / или Character.isLetter () .


0
import java.util.*;

class Class1 {
    public static void main(String[] argh) {
        boolean ans = CheckNumbers("123");
        if (ans == true) {
            System.out.println("String contains numbers only");
        } else {
            System.out.println("String contains other values as well");

        }
    }


    public static boolean CheckNumbers(String input) {
        for (int ctr = 0; ctr < input.length(); ctr++) {
            if ("1234567890".contains(Character.valueOf(input.charAt(ctr)).toString())) {
                continue;
            } else {
                return false;
            }
        }
        return true;
    }
}

0
Character first_letter_or_number = query.charAt(0);
                //------------------------------------------------------------------------------
                if (Character.isDigit())
                {

                }
                else if (Character.isLetter())
                {

                }

0

Рабочий тестовый пример

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

public class PaserNo {

    public static void main(String args[]) {

        String text = "gg";

        if (!StringUtils.isBlank(text)) {
            if (stringContainsNumber(text)) {
                int no=Integer.parseInt(text.trim());
                System.out.println("inside"+no);

            } else {
                System.out.println("Outside");
            }
        }
        System.out.println("Done");
    }

    public static boolean stringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }
}

Тем не менее, ваш код может быть разбит на «1a» и т. Д., Поэтому вам нужно проверить исключение

if (!StringUtils.isBlank(studentNbr)) {
                try{
                    if (isStringContainsNumber(studentNbr)){
                    _account.setStudentNbr(Integer.parseInt(studentNbr.trim()));
                }
                }catch(Exception e){
                    e.printStackTrace();
                    logger.info("Exception during parse studentNbr"+e.getMessage());
                }
            }

Метод проверки нет, строка или нет

private boolean isStringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }

0

Это плохая практика - включать или исключать любые исключения в такой типичный сценарий.

Поэтому parseInt () нехорошо, но регулярное выражение является элегантным решением для этого, но позаботьтесь о следующем:
-fractions -отрицательные
числа
-decimal разделитель может отличаться по контурам (например, ',' или '.')
-Sometimes разрешено иметь так называемый разделитель тысяч, например, пробел или запятую, например, 12,324,1000,355

Чтобы обработать все необходимые случаи в вашем приложении, вы должны быть осторожны, но это регулярное выражение охватывает типичные сценарии (положительный / отрицательный и дробный, разделенные точкой): ^ [- +]? \ D *.? \ D + $
For тестирование, я рекомендую regexr.com .


0

Слегка измененная версия Адама Бодроги:

public class NumericStr {


public static void main(String[] args) {
    System.out.println("Matches: "+NumericStr.isNumeric("20"));         // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("20,00"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30,000.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("-2980"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("$20"));            // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("jdl"));            // Should be false
    System.out.println("Matches: "+NumericStr.isNumeric("2lk0"));           // Should be false
}

public static boolean isNumeric(String stringVal) {
    if (stringVal.matches("^[\\$]?[-+]?[\\d\\.,]*[\\.,]?\\d+$")) {
        return true;
    }

    return false;
}
}

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.