Як перевірити, чи є рядок рядком на Java


886

Як би ви перевірили, чи є рядком число, перш ніж його розбирати?


36
Усі рішення, запропоновані за допомогою регулярних виразів, не працюватимуть для шістнадцяткових чисел.
Оскар Кастібланко

і передача нульового рядка у функції match (...) призведе до виключення NullPointer.
Hitesh Sahu

Див. Відповідь Макса Малиша про стисле рішення Java 8 без сторонніх бібліотек.
Енді Томас

Нулі рядки @HiteshSahu здаються витончено обробленими в останній версії (включаючи Java 6.x та 7.x)
життєвий баланс

Усі рішення, запропоновані для використання Integer.parseInt(), не зможуть проаналізувати мобільні номери NumberFormatException.
Не помилка

Відповіді:


691

З Apache Commons Lang 3.5 і вище: NumberUtils.isCreatableабо StringUtils.isNumeric.

З Apache Commons Lang 3.4 і нижче: NumberUtils.isNumberабо StringUtils.isNumeric.

Ви також можете використовувати StringUtils.isNumericSpaceповернення trueдля порожніх рядків і ігнорувати внутрішні пробіли в рядку. Ще один спосіб - це використання, NumberUtils.isParsableякий в основному перевіряє кількість, яке можна проаналізувати відповідно до Java. (Зв'язані javadocs містять докладні приклади для кожного методу.)


59
StringUtils.isNumeric()ймовірно, тут не було б доречним, оскільки він перевіряє, чи рядок є послідовністю цифр. Було б добре для більшості вхідних даних, але це не так для цифр із десятковою комою, розділових груп тощо.
Джефф Меркадо

42
винаходити колесо, тому що ти не включаєш цілу бібліотеку, оскільки тобі потрібна функція 3 рядків в одному місці.
dalvarezmartinez1

12
Чи справді варто додати цілу бібліотеку для цієї функції? Очевидно, що якщо він використовується з іншими речами, це чудово, але це, мабуть, надмірно, враховуючи, що люди вирішили це в одному рядку коду.
Вода

7
Не працює з негативом. І половина всіх цифр від’ємна, так що .....
Пол Дрейпер

6
@PaulDraper: Ти маєш рацію, StringUtilsне підтримує провідні знаки, але слід перевірити NumberUtils.isCreatable, чи правильно вони підтримують мінуси.
palacsint

904

Як правило, це робиться за допомогою простої функції, визначеної користувачем (тобто функція Roll-your-last "isNumeric").

Щось на зразок:

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). Це тому, що "\ d" частина 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();
}

7
Чи відповідає \ d у Java Regex лише латинські цифри? Якщо це як .NET-регулярні вирази, ви зіткнетеся з проблемою з іншими (наприклад, арабською) цифрами, як пояснено тут: blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost

3
Рішення numberFormatter, ймовірно, лише незначно краще, ніж ловити номер NumberFormatException. Я підозрюю, що найкращий спосіб - це використовувати регулярний вираз.
Chii

11
Зауважте, що .у вашому регулярному виразі буде відповідати будь-який символ, а не лише символ десяткового роздільника.
jqno

9
+1 за реалізацію витрат на пробування / улов. Це насправді жахливий підхід використовувати в довгостроковій перспективі для багаторазового використання, але насправді ми дотримуємося цього в Java.
demongolem

5
Зауважте, що таких речей, як "латинські цифри", немає, а цифри 0-9 насправді є арабськими цифрами. Люди, мабуть, знають родичів із римськими цифрами, якими користувалися люди, які розмовляли латиною, у формі I, II, III, IV, V, VI тощо. En.wikipedia.org/wiki/Arabic_numerals ; en.wikipedia.org/wiki/Roman_numerals
dantiston

152

якщо ви перебуваєте на андроїді, то вам слід використовувати:

android.text.TextUtils.isDigitsOnly(CharSequence str)

Документацію можна знайти тут

нехай це буде просто . в основному кожен може «перепрограмувати» (те саме).


4
@ kape123 :) впевнений, що "123.456" не містить цифр.
Ахмед Алехо

8
Примітка: це призводить до NPE для нульового введення. Також не працює з від’ємними числами або десятковими знаками.
gMale

2
Мені це подобається!! Я думаю, що це абсолютно для цифр. Чи не .,-
illusionJJ

Це саме те, що я шукав. Щось просте для перевірки лише цифр 0-9. Я встановлюю фільтр в декларації свого EditText, але на всякий випадок, якщо його змінили або замінили вниз по дорозі, добре також провести просту програму.
jwehrle

127

Java 8 лямбда-вирази.

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );

4
Ви також можете скористатися посиланням на метод: someString.chars (). AllMatch (Характер :: isDigit)
Wienczny

3
Приємно, але все-таки він винаходить колесо, як майже всі "рішення" тут. Крім того, не працює на "null" (як майже всі інші).
qben

8
Ця відповідь є стислою, простою та читаною. Ви майже можете прочитати його як англійська - "символи всі збігаються цифри". Тут не потрібні сторонні бібліотеки. Він не використовує винятків у не виняткових випадках. Це має стати прийнятою відповіддю.
Енді Томас

14
Що він буде виробляти для "-1"?
Balázs Németh

2
Не правильна відповідь. Числовий рядок може містити нечислові символи (напр. "." Або "-") і все ще бути ідеально числовими. Наприклад, 0,5, -1 і 1000 не зможуть відповісти цією відповіддю, і все ж вони є цілком числовими.
Симеон Г

125

Як @CraigTP згадував у своїй чудовій відповіді, у мене також є подібні проблеми щодо використання винятків, щоб перевірити, чи є рядок числовим чи ні. Тому я закінчую розбиття рядка та використання 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 - кількість символів у рядку, було б більш обчислювально ефективнішим, ніж порівняння регулярних виразів.

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

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

4
Невже десятковий роздільник також не спричинить це?
Жан-Франсуа Корбетт

1
@ Jean-FrançoisCorbett: Добре, я оновив код на новий, який приймає десяткові роздільники.
Ібрагім Короткий

2
Чи знака -ve не виконує цю функцію?
java_mouse

3
Виклик toCharArray()створить копію масиву в об'єкті String, оскільки рядки незмінні. Можливо, швидше використовувати charAt(int index)метод на об'єкті String безпосередньо.
Майк Кучера

2
Буде чи генерувати , StringIndexOutOfBoundsExceptionколи передається рядок з довжиною 0. Може бути встановлена зif(str.length() == 0) return false;
samgak

43

Бібліотека гуави Google забезпечує хороший допоміжний метод , щоб зробити це: Ints.tryParse. Ви використовуєте його як, Integer.parseIntале він повертається, nullа не кидає виняток, якщо рядок не аналізує дійсне ціле число. Зауважте, що він повертає Integer, а не int, тому вам доведеться перетворити / автоматично повернути його до 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 вище. Не є винятком обробка накладних витрат під покривалами при їх виконанні.


Остерігайтеся, що це може кинути NPE у випадку, якщо аргумент недійсний.
Вадим

30

Не використовуйте Винятки для перевірки ваших цінностей. Використовуйте Util libs замість апаш NumberUtils:

NumberUtils.isNumber(myStringValue);

Редагувати :

Зауважте, що якщо ваш рядок починається з 0, NumberUtils буде інтерпретувати ваше значення як шістнадцятковий.

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false

7
Прийнята відповідь на три роки раніше вже висвітлена Number.isNumber().
Енді Томас

Я не думаю, що так. Він був оновлений або op змінив прийняту відповідь. Я пам'ятаю, що прийнята відповідь не охоплювала NumberUtils, тому я додав свою відповідь. Але дякую за коментар
Goot

2
@Goot - історія прийнятої відповіді показує, що вона Number.isNumber()була присутня з першої версії відповіді, датованої 24 вересня 1212 року о 17:01.
Енді Томас

@Goot, це досить добре, оскільки він також охоплює перевірку десяткового значення, на відміну від StringUtils.
Хена Хуссей

24

Чому всі наполягають на винятку / регулярному вираженні?

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

Що я тут зробив, це взяти регулярний вираз, методи 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 для потоку програми . Це приклад, чому.

Цікаво, що простий, якщо 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
Чи не складається це кожен новий регулярний вираз кожен раз? Це не дуже ефективно.
Семюель Едвін Уорд

1
@SamuelEdwinWard Те буде вся причина , я зробив цей пост ... регулярний вираз приклад використав надані відповіді інших людей, і показав , як неефективне це. Навіть якщо ви спробуєте регулярно встановити його з попередньою компіляцією заздалегідь і лише використовуючи це, різниці в часі становлять: 2587 мс для регексу, який я розмістив від інших наданих людей, 950 мс при компілюванні достроково, 144 мс, коли робите це як числовий масив (на 1 мілі ітерацій того ж рядка). Збірка заздалегідь, очевидно, допомогла б, але, на жаль, вона все ще зовсім поступається матриці ... хіба що є якась шалена оптимізація, про яку я не знаю.
Вода

Вважати, що Regex робить все швидше - це майже помилка. Якщо це одноразовий пошук, так, я розумію, але я помітив, що ефективно написаний код насправді перевершує регулярний вираз, щоб вас шокувати! Відмінний пост @Water
Yo Apps

19
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

Регулярне вираження CraigTP (показане вище) дає деякі помилкові позитиви. Наприклад, "23y4" буде зараховано до числа, оскільки "." відповідає будь-якому символу, не десятковій крапці.

Крім того, він відхилить будь-яке число за допомогою "+"

Альтернативою, яка дозволяє уникнути цих двох незначних проблем, є

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}

це повернеться trueза один плюс "+"чи мінус "-", а falseдля"0."
user85421

Хороший улов на одиничний плюс або мінус. "0" дійсне число?
користувач872985

"0."діє для Double.parseDouble()і є дійсним літералом згідно з JLS ( §3.10.2 )!
користувач85421

Створення регулярних виразів також дороге. Регулярний вираз повинен бути створений один раз і повторно використаний
Даніель Нурієв

1
ви повинні змінити його наmatches("-?\\d+([.]\\d+)?")
Бобс

14

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

boolean isNumber(String str){
        if(str.length() == 0)
            return false; //To check if string is empty

        if(str.charAt(0) == '-')
            str = str.replaceFirst("-","");// for handling -ve numbers

        System.out.println(str);

        str = str.replaceFirst("\\.",""); //to check if it contains more than one decimal points

        if(str.length() == 0)
            return false; // to check if it is empty string after removing -ve sign and decimal point
        System.out.println(str);

        return str.replaceAll("[0-9]","").length() == 0;
    }

Так ""це число , але "3.14"і "-1"нє?
Ерік Думініл

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

12

Ви можете використовувати NumberFormat#parse:

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}

Запропоновано редагування - .getInstance () відсутній. +1, оскільки це була відповідь, з якою я пішов, коли знаходив це питання.
8bitjunkie

5
Затратно, якщо використовувати їх експансивно
Даніель Нурієв

1
Він також пройде, якщо в кінці є символи сміття value.
Брайан Уайт

Це створило б питання про сонар, якщо ви не
увійдете

1
Це працювало для формату чисел 0x0001, де Double.parseDouble не працював. +1
Seabass77


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

5

Щоб відповідати лише позитивним цілим числом десяти, що містить лише цифри 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();
}

5

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

Особливості:

  1. Видаляє зайві нулі ["12.0000000" -> "12"]
  2. Видаляє зайві нулі ["12.0580000" -> "12.058"]
  3. Вилучає нечислові символи ["12.00sdfsdf00" -> "12"]
  4. Обробляє негативні значення рядка ["-12,020000" -> "-12.02"]
  5. Видаляє кілька крапок ["-12.0.20.000" -> "-12.02"]
  6. Без зайвих бібліотек, лише стандартна 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

Регекс-відповідність

Ось ще один приклад оновленого регулярного вирівнювання «CraigTP» з більшою кількістю перевірок.

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. Лише один негативний знак -дозволений і повинен бути на початку.
  2. Після від'ємного знаку повинна бути цифра.
  3. .Допускається лише один десятковий знак .
  4. Після десяткових знаків має бути цифра.

Тест Regex

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

Винятки дорогі, але в цьому випадку 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);

}

}

Взагалі, я думаю, що такий тип коду буде використовуватися для перевірки речей, таких як введений ввід. У такому випадку швидкість не є врахуванням, і робити щось таке потворне, як кидати виняток для перевірки на номер чи не номер - неправильно.
користувач872985

Можливо ні. Введене введення, як правило, перевіряється компонентом інтерфейсу, де помилки можуть бути показані негайно перед надсиланням значення. Можливо, більш поширеним є валідація рядків з великих вхідних текстових файлів - де важлива продуктивність. Мета моєї відповіді тут - звернутися до твердження "винятки повільні" у прийнятій відповіді. Складний гегекс набагато дорожчий. І в моєму коді взагалі немає «потворного кидка» - просто більш швидкий спосіб виявити порушення. При підході перевірки спочатку та обчислення ви зробите два проходи через вхід: один для перевірки, а потім інший для перетворення.
ChrisCantrell

5

// перевірте нижче код

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

Питання говорить "числовий", який може включати не цілі значення.
rghome

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

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

Ви можете використовувати об’єкт java.util.Scanner.

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

2

Я змінив рішення 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

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, який може бути недійсним при розборі не вдалося. Більш хижим варіантом може бути передача int [1] як вихідного параметра.
фортран

Так, я пам’ятаю дискусію про те, чому у Java немає вихідних параметрів. але, здається, повернення Integer (як нульове, якщо це потрібно) теж буде добре, хоча я не знаю про продуктивність Java щодо боксу / розпакування.
OregonGhost

4
Мені подобається C # настільки ж, як наступний хлопець, але не потрібно додавати фрагмент коду .NET C # для питання Java, коли функцій у Java не існує
Shane

Це створило б питання про сонар, якщо ви не
увійдете

2

Проаналізуйте його (тобто з Integer#parseInt) і просто зловіть виняток. =)

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

Якщо ви не хочете розбирати його (або розбирати його дуже, дуже рідко), можливо, ви хочете зробити це інакше, звичайно.


1
Затратно, якщо використовувати їх експансивно
Даніель Нурієв

Це створило б питання про сонар, якщо ви не
увійдете

Double.parseDouble
Alex78191

2

Ви можете використовувати NumberUtils.isCreatable () від Apache Commons Lang .

Оскільки NumberUtils.isNumber буде застарілим у 4.0, то використовуйте замість NumberUtils.isCreatable ().


2

Потік Java 8, вираз лямбда, функціональний інтерфейс

Усі оброблені випадки ( нульовий рядок, рядок порожній тощо )

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

2

Я проілюстрував деякі умови перевірки чисел і десяткових знаків без використання API,

Перевірте Fix Length 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");

Сподіваюсь, що це допоможе багатьом.


2

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

Він перевіряє максимум один знак мінус і максимум одну десяткову точку.

Ось кілька прикладів та їх результати:

"1", "-1", "-1.5" та "-1.556" повертають істинні

"1..5", "1A.5", "1.5D", "-" і "--1" повертаються помилково

Примітка: Якщо потрібно, ви можете змінити це, щоб прийняти параметр 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;
}

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

Ось ще один метод у випадку, якщо ви хочете дозволити floats Цей метод нібито дозволяє числам у формі передати 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;
}

О, гарне запитання. Я думаю, що це працює лише цілими числами звичайного типу. Спочатку було створено метод фільтрації вхідних телефонних номерів та підрахунку чисел.
XForCE07
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.