Come verifichi se una stringa fosse un numero prima di analizzarlo?
Integer.parseInt()
non riescono ad analizzare i numeri di cellulare NumberFormatException
.
Come verifichi se una stringa fosse un numero prima di analizzarlo?
Integer.parseInt()
non riescono ad analizzare i numeri di cellulare NumberFormatException
.
Risposte:
Con Apache Commons Lang 3.5 e versioni successive: NumberUtils.isCreatable
o StringUtils.isNumeric
.
Con Apache Commons Lang 3.4 e precedenti: NumberUtils.isNumber
o StringUtils.isNumeric
.
Puoi anche usare StringUtils.isNumericSpace
quali restituisce true
stringhe vuote e ignora gli spazi interni nella stringa. Un altro modo è usare NumberUtils.isParsable
che sostanzialmente controlla che il numero sia analizzabile secondo Java. (I javadocs collegati contengono esempi dettagliati per ciascun metodo.)
StringUtils.isNumeric()
probabilmente non sarebbe appropriato qui poiché controlla solo se la stringa è una sequenza di cifre. Andrebbe bene per la maggior parte degli ints, ma non così per i numeri con decimali, separatori di gruppi, ecc.
StringUtils
non supporta i segni guida ma dovresti controllare NumberUtils.isCreatable
, supporta correttamente i negativi.
Questo viene generalmente fatto con una semplice funzione definita dall'utente (ad es. Funzione "isNumeric" di Roll-your-own).
Qualcosa di simile a:
public static boolean isNumeric(String str) {
try {
Double.parseDouble(str);
return true;
} catch(NumberFormatException e){
return false;
}
}
Tuttavia, se stai chiamando questa funzione molto e ti aspetti che molti dei controlli falliscano a causa del fatto che non sono un numero, l'esecuzione di questo meccanismo non sarà eccezionale, dal momento che fai affidamento sulle eccezioni generate per ogni errore, che è un'operazione piuttosto costosa.
Un approccio alternativo potrebbe essere quello di utilizzare un'espressione regolare per verificare la validità di essere un numero:
public static boolean isNumeric(String str) {
return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
}
Fai attenzione al meccanismo RegEx sopra, tuttavia, poiché fallirà se stai usando cifre non arabe (cioè numeri diversi da 0 a 9). Questo perché la parte "\ d" di RegEx corrisponderà solo a [0-9] e di fatto non è a livello internazionale consapevole numericamente. (Grazie a OregonGhost per averlo segnalato!)
O anche un'altra alternativa è usare l'oggetto java.text.NumberFormat incorporato di Java per vedere se, dopo aver analizzato la stringa, la posizione del parser è alla fine della stringa. In tal caso, possiamo supporre che l'intera stringa sia numerica:
public static boolean isNumeric(String str) {
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
.
nella tua regex corrisponderà a qualsiasi carattere, non solo al carattere separatore decimale.
se sei su Android, allora dovresti usare:
android.text.TextUtils.isDigitsOnly(CharSequence str)
la documentazione è disponibile qui
mantienilo semplice . per lo più tutti possono "riprogrammare" (la stessa cosa).
.
,-
Java 8 espressioni lambda.
String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
Come aveva citato @CraigTP nella sua eccellente risposta, ho anche problemi di prestazioni simili sull'uso delle Eccezioni per verificare se la stringa è numerica o meno. Quindi finisco per dividere la stringa e usare java.lang.Character.isDigit()
.
public static boolean isNumeric(String str)
{
for (char c : str.toCharArray())
{
if (!Character.isDigit(c)) return false;
}
return true;
}
Secondo il Javadoc , Character.isDigit(char)
riconoscerà correttamente le cifre non latine. Per quanto riguarda le prestazioni, penso che un semplice numero N di confronti in cui N è il numero di caratteri nella stringa sarebbe più efficiente dal punto di vista computazionale rispetto a una corrispondenza regex.
AGGIORNAMENTO: Come sottolineato da Jean-François Corbett nel commento, il codice sopra riportato convaliderebbe solo numeri interi positivi, che copre la maggior parte del mio caso d'uso. Di seguito è riportato il codice aggiornato che convalida correttamente i numeri decimali in base alle impostazioni internazionali predefinite utilizzate nel sistema, presupponendo che il separatore decimale si presenti solo una volta nella stringa.
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;
}
toCharArray()
creerà una copia dell'array nell'oggetto String perché le stringhe sono immutabili. Probabilmente più veloce da usare direttamente il charAt(int index)
metodo sull'oggetto String.
StringIndexOutOfBoundsException
quando passa una stringa di lunghezza 0. Può essere fissato conif(str.length() == 0) return false;
Biblioteca Guava di Google offre un metodo di supporto piacevole per fare questo: Ints.tryParse
. Lo usi come, Integer.parseInt
ma restituisce null
anziché generare un'eccezione se la stringa non analizza un numero intero valido. Nota che restituisce Integer, non int, quindi devi convertirlo / autobox in int.
Esempio:
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
Tuttavia, a partire dalla versione corrente - Guava r11 - è ancora contrassegnato con @Beta.
Non l'ho confrontato. Guardando il codice sorgente c'è un certo sovraccarico da molti controlli di sanità mentale ma alla fine usano Character.digit(string.charAt(idx))
, simile, ma leggermente diverso dalla risposta di @Ibrahim sopra. Non vi è alcuna eccezione nella gestione delle spese generali sotto le coperte nella loro implementazione.
Non utilizzare le eccezioni per convalidare i valori. Usa le librerie Util invece di apache NumberUtils:
NumberUtils.isNumber(myStringValue);
Modifica :
Si noti che, se la stringa inizia con uno 0, NumberUtils interpreterà il valore come esadecimale.
NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
Number.isNumber()
.
Number.isNumber()
era presente dalla prima versione della risposta, datata 24 settembre 12 alle 17:01.
Perché tutti spingono per soluzioni di eccezione / regex?
Anche se riesco a capire che la maggior parte delle persone sta bene usando try / catch, se vuoi farlo frequentemente ... può essere estremamente faticoso.
Quello che ho fatto qui è stato prendere il regex, i metodi parseNumber () e il metodo di ricerca dell'array per vedere quale era il più efficiente. Questa volta, ho solo guardato i numeri interi.
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;
}
I risultati nella velocità che ho ottenuto sono stati:
Done with: for (int i = 0; i < 10000000; i++)...
With only valid numbers ("59815833" and "-59815833"):
Array numeric took 395.808192 ms [39.5808192 ns each]
Regex took 2609.262595 ms [260.9262595 ns each]
Exception numeric took 428.050207 ms [42.8050207 ns each]
// Negative sign
Array numeric took 355.788273 ms [35.5788273 ns each]
Regex took 2746.278466 ms [274.6278466 ns each]
Exception numeric took 518.989902 ms [51.8989902 ns each]
// Single value ("1")
Array numeric took 317.861267 ms [31.7861267 ns each]
Regex took 2505.313201 ms [250.5313201 ns each]
Exception numeric took 239.956955 ms [23.9956955 ns each]
// With Character.isDigit()
Array numeric took 400.734616 ms [40.0734616 ns each]
Regex took 2663.052417 ms [266.3052417 ns each]
Exception numeric took 401.235906 ms [40.1235906 ns each]
With invalid characters ("5981a5833" and "a"):
Array numeric took 343.205793 ms [34.3205793 ns each]
Regex took 2608.739933 ms [260.8739933 ns each]
Exception numeric took 7317.201775 ms [731.7201775 ns each]
// With a single character ("a")
Array numeric took 291.695519 ms [29.1695519 ns each]
Regex took 2287.25378 ms [228.725378 ns each]
Exception numeric took 7095.969481 ms [709.5969481 ns each]
With null:
Array numeric took 214.663834 ms [21.4663834 ns each]
Regex took 201.395992 ms [20.1395992 ns each]
Exception numeric took 233.049327 ms [23.3049327 ns each]
Exception numeric took 6603.669427 ms [660.3669427 ns each] if there is no if/null check
Disclaimer: non sto affermando che questi metodi sono ottimizzati al 100%, sono solo per la dimostrazione dei dati
Eccezioni vinte se e solo se il numero è composto da 4 caratteri o meno, e ogni stringa è sempre un numero ... nel qual caso, perché anche avere un controllo?
In breve, è estremamente doloroso imbattersi frequentemente in numeri non validi con il tentativo / cattura, il che ha senso. Una regola importante che seguo sempre è MAI utilizzare try / catch per il flusso del programma . Questo è un esempio del perché.
È interessante notare che il semplice se char <0 || > 9 è stato estremamente semplice da scrivere, facile da ricordare (e dovrebbe funzionare in più lingue) e vince quasi tutti gli scenari di test.
L'unico aspetto negativo è che suppongo che Integer.parseInt () potrebbe gestire numeri non ASCII, mentre il metodo di ricerca dell'array non lo fa.
Per quelli che si chiedono perché ho detto che è facile ricordare l'array di personaggi uno, se sai che non ci sono segni negativi, puoi facilmente scappare con qualcosa di condensato come questo:
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;
Infine, come nota finale, ero curioso dell'operatore incaricato nell'esempio accettato con tutti i voti in su. Aggiungendo nell'assegnazione di
double d = Double.parseDouble(...)
non è solo inutile poiché non si utilizza nemmeno il valore, ma si spreca il tempo di elaborazione e aumenta il tempo di esecuzione di alcuni nanosecondi (il che ha portato a un aumento di 100-200 ms nei test). Non riesco a capire perché qualcuno dovrebbe farlo dal momento che in realtà è un lavoro extra per ridurre le prestazioni.
Penseresti che sarebbe ottimizzato ... anche se forse dovrei controllare il bytecode e vedere cosa sta facendo il compilatore. Questo non spiega perché mi sia sempre apparso più lungo, anche se in qualche modo è stato ottimizzato ... quindi mi chiedo cosa stia succedendo. Come nota: per più lungo, intendo eseguire il test per 10000000 iterazioni e l'esecuzione di quel programma più volte (10x +) ha sempre mostrato che è più lento.
EDIT: aggiornato un test per Character.isDigit ()
public static boolean isNumeric(String str)
{
return str.matches("-?\\d+(.\\d+)?");
}
L'espressione regolare di CraigTP (mostrata sopra) produce alcuni falsi positivi. Ad esempio "23y4" verrà conteggiato come un numero perché "." corrisponde a qualsiasi carattere non al punto decimale.
Inoltre rifiuterà qualsiasi numero con un '+' iniziale
Un'alternativa che evita questi due problemi minori è
public static boolean isNumeric(String str)
{
return str.matches("[+-]?\\d*(\\.\\d+)?");
}
true
per un singolo più "+"
o meno "-"
, e false
per"0."
matches("-?\\d+([.]\\d+)?")
Possiamo provare a sostituire tutti i numeri della stringa specificata con ("") ovvero uno spazio vuoto e se dopo che la lunghezza della stringa è zero, allora possiamo dire che la stringa data contiene solo numeri. [Se hai trovato utile questa risposta, prendi in considerazione la possibilità di votarla] Esempio:
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;
}
""
è un numero, ma "3.14"
e "-1"
non sono?
Puoi usare NumberFormat#parse
:
try
{
NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
// Not a number.
}
value
.
Se si utilizza Java per sviluppare l'app Android, è possibile utilizzare la funzione TextUtils.isDigitsOnly .
Ecco la mia risposta al problema.
Una cattura tutte metodo comodo che può essere utilizzato per analizzare qualsiasi stringa con qualsiasi tipo di parser: isParsable(Object parser, String str)
. Il parser può essere un Class
o un object
. Questo ti consentirà anche di utilizzare parser personalizzati che hai scritto e dovrebbe funzionare per qualsiasi scenario, ad esempio:
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");
Ecco il mio codice completo con le descrizioni dei metodi.
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;
}
}
Ecco la mia classe per verificare se una stringa è numerica. Corregge anche stringhe numeriche:
Ecco qui...
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;
}
}
Abbinamento Regex
Ecco un altro esempio di corrispondenza regex "CraigTP" aggiornata con più convalide.
public static boolean isNumeric(String str)
{
return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
Test di 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
Le eccezioni sono costose, ma in questo caso il RegEx impiega molto più tempo. Il codice seguente mostra un semplice test di due funzioni: una che utilizza eccezioni e una che utilizza regex. Sulla mia macchina la versione RegEx è 10 volte più lenta dell'eccezione.
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);
}
}
// controlla sotto il codice
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;
}
// 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;
}
}
Questo è un semplice esempio per questo controllo:
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;
}
È possibile utilizzare l'oggetto java.util.Scanner.
public static boolean isNumeric(String inputData) {
Scanner sc = new Scanner(inputData);
return sc.hasNextInt();
}
Ho modificato la soluzione di CraigTP per accettare anche la notazione scientifica e sia il punto che la virgola come separatori decimali
^-?\d+([,\.]\d+)?([eE]-?\d+)?$
esempio
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
Ecco perché mi piace l'approccio Try * in .NET. Oltre al metodo Parse tradizionale simile a quello Java, hai anche un metodo TryParse. Non sono bravo nella sintassi Java (parametri out?), Quindi ti preghiamo di considerare quanto segue come una specie di pseudo-codice. Dovrebbe rendere chiaro il concetto però.
boolean parseInteger(String s, out int number)
{
try {
number = Integer.parseInt(myString);
return true;
} catch(NumberFormatException e) {
return false;
}
}
Uso:
int num;
if (parseInteger("23", out num)) {
// Do something with num.
}
Analizzalo (cioè con Integer#parseInt
) e prendi semplicemente l'eccezione. =)
Per chiarire: la funzione parseInt verifica se è in grado di analizzare il numero in ogni caso (ovviamente) e se si desidera analizzarlo comunque, non si subirà alcun hit di prestazione eseguendo effettivamente l'analisi.
Se non si desidera analizzarlo (o analizzarlo molto, molto raramente), si potrebbe desiderare di farlo in modo diverso, ovviamente.
Puoi usare NumberUtils.isCreatable () da Apache Commons Lang .
Poiché NumberUtils.isNumber sarà deprecato in 4.0, utilizzare invece NumberUtils.isCreatable ().
Java 8 Stream, espressione lambda, interfaccia funzionale
Tutti i casi gestiti ( stringa null, stringa vuota ecc. )
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();
Ho illustrato alcune condizioni per controllare numeri e decimali senza utilizzare alcuna API,
Controllare la lunghezza fissa Numero di 1 cifra
Character.isDigit(char)
Controlla il numero di lunghezza fissa (supponiamo che la lunghezza sia 6)
String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");
Controlla il numero della lunghezza variabile tra (Supponi da 4 a 6 lunghezze)
// {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");
Controlla il numero decimale della lunghezza variabile tra (Supponiamo che la lunghezza sia compresa tra 4 e 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");
Spero che possa aiutare molti.
Sulla base di altre risposte che ho scritto il mio e non utilizza modelli o analisi con controllo delle eccezioni.
Verifica un massimo di un segno meno e verifica un massimo di un punto decimale.
Ecco alcuni esempi e i loro risultati:
"1", "-1", "-1.5" e "-1.556" restituiscono true
"1..5", "1A.5", "1.5D", "-" e "--1" restituiscono false
Nota: se necessario, è possibile modificarlo per accettare un parametro Locale e passarlo nelle chiamate DecimalFormatSymbols.getInstance () per utilizzare una Locale specifica anziché quella corrente.
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;
}
Ecco due metodi che potrebbero funzionare. (Senza utilizzare le eccezioni). Nota: Java è un valore passa per impostazione predefinita e il valore di una stringa è l'indirizzo dei dati dell'oggetto della stringa. Quindi, quando lo stai facendo
stringNumber = stringNumber.replaceAll(" ", "");
Hai modificato il valore di input per non avere spazi. Puoi rimuovere quella linea se vuoi.
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;
}
Ecco un altro metodo nel caso in cui si desideri consentire i float Questo metodo presumibilmente consente ai numeri nel modulo di passare 1.123.123.123.123.123.123 l'ho appena fatto e penso che abbia bisogno di ulteriori test per assicurarsi che funzioni.
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;
}