Как проверить, является ли строка числом, прежде чем разбирать ее?
Обычно это делается с простой пользовательской функции (т. е. крен-ваш-собственный и"статистика" и функции).
Что-то вроде:
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.
}
Будьте осторожны с выше механизм регулярных выражений, хотя, как она будет выполнена, если вы're, используя арабские цифры (т. е. цифры от 0 до 9). Это потому, что " В\Д" в рамках регулярное выражение будет соответствовать только [0-9] и эффективно это'т международно численно курсе. (Спасибо OregonGhost за указание на это!)
Или еще другой вариант-использовать Java'ы встроенный в Java.текст.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();
}
С 3.5 Апач Викискладе Ланг и выше: NumberUtils.isCreatable
или StringUtils .статистика
.
С Апач Викискладе Ланг 3.4 и ниже: NumberUtils.ечисло
или StringUtils .статистика
.
Вы также можете использовать StringUtils .isNumericSpace
, который возвращает true для пустой строки и игнорирует внутреннее пространство в строке. Другой способ-использовать StringUtils .isParsable
, который в основном проверяет номер оформленной в соответствии с Java. (Связанной документации содержит подробные примеры для каждого метода.)
если вы находитесь на Android, то вы должны использовать:
android.text.TextUtils.isDigitsOnly(CharSequence str)
документацию можно найти здесь
<и><б>сохранить его простым</б></я и GT;. в основном все могут назальный перепрограммировать; (то же самое).
Как @CraigTP упомянул в своем отличный ответ, у меня тоже похожие проблемы с производительностью на использование исключений для проверки, является ли строка является числовым или нет. Так что я в конечном итоге разделение строки и использовать Ява.яз.Характер.isDigit()
.
public static boolean isNumeric(String str)
{
for (char c : str.toCharArray())
{
if (!Character.isDigit(c)) return false;
}
return true;
}
По документации, `характер.isDigit(Чара) будет правильно распознает латинские цифры. Производительность-мудрый, я думаю, что простое число n сравнений, где n-количество символов в строке будет более вычислительно эффективным, чем регулярное выражение соответствия.
Обновление: как указал Жан-ФрансуаçОИ Корбетт в комментарий, приведенный выше код должен проверить только положительных чисел, который охватывает большую часть моего варианта использования. Ниже приведен обновленный код, который проверяет, правильно десятичных чисел в соответствии с локалью по умолчанию, используемые в вашей системе, при условии, что десятичный разделитель встречаются в строке только один раз.
public static boolean isStringNumeric( String str )
{
DecimalFormatSymbols currentLocaleSymbols = DecimalFormatSymbols.getInstance();
char localeMinusSign = currentLocaleSymbols.getMinusSign();
if ( !Character.isDigit( str.charAt( 0 ) ) && str.charAt( 0 ) != localeMinusSign ) return false;
boolean isDecimalSeparatorFound = false;
char localeDecimalSeparator = currentLocaleSymbols.getDecimalSeparator();
for ( char c : str.substring( 1 ).toCharArray() )
{
if ( !Character.isDigit( c ) )
{
if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
{
isDecimalSeparatorFound = true;
continue;
}
return false;
}
}
return true;
}
Java 8 лямбда-выражения.
String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
В Google'библиотека гуавы обеспечивает хороший вспомогательный метод, чтобы сделать это: ИНЦ.метод tryparse
. Вы используете его как целое.parseInt-но он возвращает значение null, а не бросать исключение, если строка не преобразовываться в число. Обратите внимание, что она возвращает целое число, не 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
Однако, по состоянию на текущей версии -- гуавы Р11-это по-прежнему отмечен @бета.
Я не'т сопоставив ее. Глядя на исходный код, есть некоторые накладные расходы от проверки работоспособности, но в конце концов они используют характер.цифра(строка.используя метод charat(индекс))
, похож, но немного отличается от, ответ от @Ибрагим выше. Нет обработки исключений над головой под одеяло в их реализации.
Не используйте исключения для проверки ваших ценностей. Использовать утиль либы, а не как Apache NumberUtils:
NumberUtils.isNumber(myStringValue);
Редактировать:
Пожалуйста, обратите внимание, что если ваша строка начинается с 0, NumberUtils будет интерпретировать значение как шестнадцатеричное.
NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
Почему все стремятся за исключением решений/регулярное выражение?
Хотя я могу понять, большинство людей не в порядке с использование конструкции try/поймать, если вы хотите делать это часто... это может быть очень утомительным.
То, что я сделал здесь был взять регулярное выражение, в 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% оптимизированы, они're просто для демонстрации данных
Исключения будут, если и только если число 4 или менее символов, и каждая строка всегда рядом... в таком случае, зачем вообще чек?
Короче, это очень больно, если вы часто в поврежденных числа с try/catch, в которых есть смысл. Важное правило я всегда следую-это никогда не использовать try/catch для выполнения программы. Это пример, почему.
Интересно, просто, если чар <0 || >9 был предельно простым, чтобы написать, легко запомнить (и должен работать на нескольких языках) и выигрывает почти во всех тестовых сценариях.
Единственным недостатком является то, что я'м угадывание целого числа.parseInt() может обрабатывать номера чисел в формате ASCII, а методом перебора массива не.
Для тех, кому интересно, почему я сказал, что это'ы легко запомнить в массив символов, если вы знаете, там's отсутствие негативных признаков, вы можете легко уйти с чем-то сжаты, как это:
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(...)
это не только бесполезно, так как вы Don'т даже использовать значение, но это пустая трата времени обработки и увеличение времени выполнения на несколько наносекунд (что привело к увеличению 100-200 МС в тестах). Я могу'т вижу, почему кто-то делать, потому что на самом деле является дополнительной работы, чтобы снизить производительность.
Вы'd не думаю, что будет оптимизированными... хотя, возможно, я должен проверить байт-код и увидеть, что компилятор делает. Это вовсе'т объяснить, почему он всегда появился как более длительная, хотя для меня, если он как-то оптимизирован из... поэтому мне интересно, что's идя дальше. Как примечание: по завершении, я имею в виду запуск теста для итераций 10000000, и запускает эту программу несколько раз (10х+) всегда показывал он будет медленнее.
Редактировать: обновлен тест на характер.isDigit()
public static boolean isNumeric(String str)
{
return str.matches("-?\\d+(.\\d+)?");
}
CraigTP's в регулярных выражениях (см. выше) и производит некоторые ложных срабатываний. Е. Г. я 23y4 " и; будет учитываться как количество, потому что '.' соответствует любому символу, не запятой.
Также он будет отвергать любое число с ведущим '+'
Альтернативу, которая избегает этих двух незначительных проблем<БР>
public static boolean isNumeric(String str)
{
return str.matches("[+-]?\\d*(\\.\\d+)?");
}
Можно попробовать заменить все числа из заданной строки С (на" глаз") т. е. пустое пространство и если после этого длина строки равна нулю, то можно сказать, что данная строка содержит только цифры. [Если вы нашли этот ответ полезным, пожалуйста, рассмотреть до голосования] Пример:
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;
}
Вы можете использовать NumberFormat#parse
:
try
{
NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
// Not a number.
}
Если вы используете Java для разработки Android приложения, вы можете с помощью TextUtils.isDigitsOnly.
Здесь был мой ответ на проблему.
Все для метод удобства, который можно использовать для анализа любую строку с любым типом парсера: isParsable(парсер объекта ул., строка)
. Парсер может быть "класс" или "объект". Это также позволяет использовать пользовательские Парсеры вы'вэ написано и должно работать для когда-либо случае, например:
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");
Здесь's мой код с описания метода.
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;
}
}
Исключением являются дорогими, но в данном случае регулярное выражение занимает гораздо больше времени. Код, приведенный ниже показывает простой тест из двух функций, одна из которых использует исключения и один с помощью 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);
}
}
регулярное выражение соответствия
Вот еще один пример повышен на "CraigTP" в регулярное выражение сопоставления с более проверок.
public static boolean isNumeric(String str)
{
return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
проверка регулярных выражений
1 -- **VALID**
1. -- INVALID
1.. -- INVALID
1.1 -- **VALID**
1.1.1 -- INVALID
-1 -- **VALID**
--1 -- INVALID
-1. -- INVALID
-1.1 -- **VALID**
-1.1.1 -- INVALID
// пожалуйста, проверьте ниже код
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;
}
Хорошо выполняя подход, избегая попробовать-поймать и обработки отрицательных чисел и научной нотации.
Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );
public static boolean isNumeric( String value )
{
return value != null && PATTERN.matcher( value ).matches();
}
Чтобы соответствовать только положительные основания-десять целых чисел, который содержит только цифры ASCII, используйте:
public static boolean isNumeric(String maybeNumeric) {
return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}
Вот мой класс для проверки, если строка является числовым. Он также исправляет числовые строки:
Здесь вы идете...
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;
}
}
// 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;
}
}