Java-рядок - подивіться, чи містить рядок лише цифри, а не букви


196

У мене є рядок, який я завантажую протягом усієї програми, і вона змінюється від цифр до букв тощо. У мене є просте 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
Використовуючи boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));форму потокового API API для Max Malyshпублікації.
Яш

Відповіді:


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()повертає істину тоді і лише тоді, коли це повний збіг від початку до кінця.
Chthonic Project

4
"^ -? \ d + \.? \ d * $" порівнюватиме цілий рядок і відповідатиме лише, якщо це дійсне число (включені негативи та десяткові дроби). Наприклад, він відповідає 1, 10, 1,0, -1, -1,0 і т.д. Він також збігатиметься на "1." але це часто можна розібрати в будь-якому випадку.

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

Що з коми або крапки для чисел, які не є цілими числами?
nibbana

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замість створення зайвого масиву, а інший використовує IntStreamchar-коди
  • Додайте негайну перерву, якщо для тестових справ із циклами знайдено нецифровий розряд
  • Повернути помилку для порожнього рядка для петельних тестових випадків

Оновлено 23 лютого 2018 року

  • Додайте ще один тестовий випадок (найшвидший!), Який порівнює значення знаку без використання потоку

1
Якщо ви подивитеся на код toCharArray, він виділяє масив char та копіює символи (я думаю, що це може бути дорогим). Що робити, якщо ви просто повторюєте рядок за допомогою індексу та charAt, чи буде це швидше? Було б цікаво також, якби ви могли додати рішення від Енді до своїх тестів: булевий isNum = text.chars (). AllMatch (c -> c> = 48 && c <= 57)
Aldo Canepa

8

Для того, щоб просто перевірити рядок, що він містить лише ALPHABETS, використовуйте наступний код:

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

Для того щоб просто перевірити рядок, що він містить лише NUMBER, використовуйте наступний код:

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

Сподіваюся, це комусь допоможе!


3

boolean 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 Lang надає org.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 Я погоджуюся, що винятки не є чудовим способом вирішення очікуваних випадків, які можуть виникнути. Однак я думаю, що важко сказати, чи не було б хіта на виставу без більшого контексту.
pseudoramble

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 () не приємно, але регулярний вираз елегантне рішення для цього, але подбати про наступне:
-дробей
-негативних числа
десяткове ціле Сепаратор може відрізнятися в contries ( «» , наприклад «» або)
-Іноді дозволяється мати так званий роздільник тисяч, як пробіл або кома, наприклад, 12,324,1000.355

Щоб вирішити всі необхідні випадки у вашій програмі, ви повинні бути обережними, але цей регулярний вираз охоплює типові сценарії (позитивні / негативні та дробові, розділені крапкою): ^ [- +]? \ D *.? \ D + $
для тестування, рекомендую 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.