Comment vérifieriez-vous si une chaîne était un nombre avant de l'analyser?
Avec Apache Commons Lang 3.5 et supérieur: NumberUtils.isCreatable
ou StringUtils.isNumeric
.
Avec Apache Commons Lang 3.4 et moins: NumberUtils.isNumber
ou StringUtils.isNumeric
.
Vous pouvez également utiliser StringUtils.isNumericSpace
qui renvoie true
pour les chaînes vides et ignore les espaces internes de la chaîne. Une autre solution consiste à utiliser StringUtils.isParsable
qui vérifie si le nombre est analysable en fonction de Java. (Les javadocs liés contiennent des exemples détaillés pour chaque méthode.)
Cela se fait généralement avec une simple fonction définie par l'utilisateur (c'est-à-dire la fonction "isNumeric" à rouler soi-même).
Quelque chose comme:
public static boolean isNumeric(String str) {
try {
Double.parseDouble(str);
return true;
} catch(NumberFormatException e){
return false;
}
}
Toutefois, si vous appelez beaucoup cette fonction et si vous vous attendez à ce que bon nombre des vérifications échouent du fait que ce n'est pas un nombre, les performances de ce mécanisme ne seront pas excellentes, car vous vous fiez aux exceptions générées pour chaque défaillance. ce qui est une opération assez chère.
Une autre approche consiste à utiliser une expression régulière pour vérifier la validité d’un nombre:
public static boolean isNumeric(String str) {
return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal.
}
Soyez prudent avec le mécanisme RegEx ci-dessus, car il échouera si vous utilisez des chiffres non arabes (c'est-à-dire des chiffres autres que 0 à 9). Cela est dû au fait que la partie "\ d" de RegEx correspond uniquement à [0-9] et qu’elle n’est pas réellement informée numériquement. (Merci à OregonGhost pour l'avoir signalé!)
Ou même une autre alternative consiste à utiliser l'objet Java.text.NumberFormat intégré à Java pour voir si, après l'analyse de la chaîne, la position de l'analyseur se trouve à la fin de la chaîne. Si c'est le cas, nous pouvons supposer que la chaîne entière est numérique:
public static boolean isNumeric(String str) {
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
si vous utilisez Android, vous devez utiliser:
Android.text.TextUtils.isDigitsOnly(CharSequence str)
la documentation peut être trouvée ici
rester simple. presque tout le monde peut "reprogrammer" (la même chose).
Comme @CraigTP l'a mentionné dans son excellente réponse, je suis également préoccupé par les performances à cause de l'utilisation d'Exceptions pour tester si la chaîne est numérique ou non. Je finis donc par scinder la chaîne et utiliser Java.lang.Character.isDigit()
.
public static boolean isNumeric(String str)
{
for (char c : str.toCharArray())
{
if (!Character.isDigit(c)) return false;
}
return true;
}
Selon le Javadoc , Character.isDigit(char)
reconnaît correctement les chiffres non latins. En termes de performances, je pense qu’un simple nombre N de comparaisons, où N est le nombre de caractères de la chaîne, serait plus efficace du point de vue des calculs que la mise en correspondance rationnelle.
MISE À JOUR: Comme l'a souligné Jean-François Corbett dans le commentaire, le code ci-dessus ne validerait que les entiers positifs, ce qui couvre la majorité de mes cas d'utilisation. Vous trouverez ci-dessous le code mis à jour qui valide correctement les nombres décimaux selon les paramètres régionaux par défaut utilisés dans votre système, en partant du principe que le séparateur décimal n'apparaît qu'une seule fois dans la chaîne.
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 expressions lambda.
String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
La bibliothèque Google de goyaves fournit une méthode d'assistance Nice pour le faire: Ints.tryParse
. Vous l'utilisez comme Integer.parseInt
mais il renvoie null
plutôt que de lancer une exception si la chaîne ne s'analyse pas en un entier valide. Notez qu'il retourne Integer, pas int, vous devez donc le reconvertir/autobox en int.
Exemple:
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
Cependant, à partir de la version actuelle - Guava r11 -, il est toujours marqué @Beta.
Je ne l'ai pas évalué. En regardant le code source, il y a un peu de travail lié à de nombreuses vérifications de sécurité, mais finalement, ils utilisent Character.digit(string.charAt(idx))
, similaire mais légèrement différent de la réponse de @Ibrahim ci-dessus. Il n’ya pas d’exception de traitement des frais généraux sous les couvertures dans leur mise en œuvre.
N'utilisez pas les exceptions pour valider vos valeurs. Utilisez Util libs à la place, comme Apache NumberUtils:
NumberUtils.isNumber(myStringValue);
Modifier :
Veuillez noter que, si votre chaîne commence par 0, NumberUtils interprétera votre valeur comme étant hexadécimale.
NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
Pourquoi tout le monde fait pression pour des solutions d'exception/regex?
Bien que je puisse comprendre que la plupart des gens acceptent d'utiliser try/catch, si vous voulez le faire fréquemment ... cela peut être extrêmement pénible.
Ce que j'ai fait ici, c’est de prendre les expressions rationnelles, les méthodes parseNumber () et la méthode de recherche de tableau pour déterminer celle qui était la plus efficace. Cette fois, je n'ai regardé que des nombres entiers.
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;
}
Les résultats en vitesse que j'ai obtenus sont les suivants:
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: je ne prétends pas que ces méthodes sont optimisées à 100%, elles sont juste pour la démonstration des données
Les exceptions sont gagnées si et seulement si le nombre est inférieur ou égal à 4 caractères et si chaque chaîne est toujours un nombre ... Dans quel cas, pourquoi même avoir un contrôle?
En bref, il est extrêmement pénible de rencontrer fréquemment des nombres non valides avec le paramètre try/catch, ce qui est logique. Une règle importante que je suis toujours est NE JAMAIS utiliser try/catch pour le déroulement du programme . Ceci est un exemple pourquoi.
Fait intéressant, le simple si char <0 || > 9 était extrêmement simple à écrire, facile à retenir (et devrait fonctionner dans plusieurs langues) et remporte presque tous les scénarios de test.
Le seul inconvénient est que je suppose qu'Integer.parseInt () pourrait gérer des nombres non ASCII, contrairement à la méthode de recherche par tableau.
Pour ceux qui se demandent pourquoi j'ai dit qu'il était facile de se rappeler le tableau de caractères, si vous savez qu'il n'y a pas de signe négatif, vous pouvez facilement vous en tirer avec quelque chose de condensé comme ceci:
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;
Enfin, pour terminer, j’étais curieux de connaître l’opérateur d’assignation dans l’exemple accepté avec tous les votes. Ajout dans l'affectation de
double d = Double.parseDouble(...)
est non seulement inutile puisque vous n'utilisez même pas la valeur, mais cela gaspille du temps de traitement et augmente le temps d'exécution de quelques nanosecondes (ce qui a entraîné une augmentation des tests de 100 à 200 ms). Je ne vois pas pourquoi quelqu'un le ferait puisqu'il s'agit en fait d'un travail supplémentaire visant à réduire les performances.
Vous penseriez que cela serait optimisé ... bien que je devrais peut-être vérifier le bytecode et voir ce que fait le compilateur. Cela n’explique pas pourquoi cela m’a toujours paru aussi long, même s’il est optimisé ... je me demande donc ce qui se passe. Remarque: par plus long, j'entends exécuter le test pour 10000000 itérations, et exécuter ce programme plusieurs fois (10x +) a toujours montré qu'il était plus lent.
EDIT: Mise à jour d'un test pour Character.isDigit ()
public static boolean isNumeric(String str)
{
return str.matches("-?\\d+(.\\d+)?");
}
L'expression régulière de CraigTP (illustrée ci-dessus) produit des faux positifs. Par exemple. "23y4" sera compté comme un nombre parce que '.' correspond à n'importe quel caractère pas le point décimal.
En outre, il rejettera n'importe quel nombre précédé d'un '+'
Une alternative qui évite ces deux problèmes mineurs est de
public static boolean isNumeric(String str)
{
return str.matches("[+-]?\\d*(\\.\\d+)?");
}
Vous pouvez utiliser NumberFormat#parse
:
try
{
NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
// Not a number.
}
Si vous utilisez Java pour développer une application Android, vous pouvez utiliser TextUtils.isDigitsOnly function.
Nous pouvons essayer de remplacer tous les nombres de la chaîne donnée par (""), c’est-à-dire un espace et si ensuite la longueur de la chaîne est égale à zéro, nous pouvons dire que la chaîne donnée ne contient que des nombres. [Si vous avez trouvé cette réponse utile, merci de bien vouloir voter] Exemple:
boolean isNumber(String str){
return str.replaceAll("[0-9]","").length() == 0;
}
Voici ma réponse au problème.
Une méthode pratique qui vous permet d'analyser n'importe quelle chaîne avec n'importe quel type d'analyseur: isParsable(Object parser, String str)
. L'analyseur peut être une Class
ou une object
. Cela vous permettra également d'utiliser des analyseurs personnalisés que vous avez écrits et qui devraient fonctionner pour tous les scénarios, par exemple:
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");
Voici mon code complet avec des descriptions de méthodes.
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;
}
}
Pour ne faire correspondre que des entiers positifs de la base de données dix, contenant uniquement ASCII chiffres, utilisez:
public static boolean isNumeric(String maybeNumeric) {
return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}
Correspondance Regex
Voici un autre exemple regex mis à jour "CraigTP" correspondant à plusieurs validations.
public static boolean isNumeric(String str)
{
return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
Test 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
Une approche performante qui évite les tentatives d’essai et gère les nombres négatifs et la notation scientifique.
Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );
public static boolean isNumeric( String value )
{
return value != null && PATTERN.matcher( value ).matches();
}
Les exceptions coûtent cher, mais dans ce cas, le RegEx prend beaucoup plus de temps. Le code ci-dessous montre un test simple de deux fonctions - une utilisant des exceptions et une utilisant regex. Sur ma machine, la version RegEx est 10 fois plus lente que l'exception.
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);
}
}
Voici ma classe pour vérifier si une chaîne est numérique. Il corrige également les chaînes numériques:
Voici...
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;
}
}
// s'il vous plaît vérifier ci-dessous le code
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;
}
Ceci est un exemple simple pour cette vérification:
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;
}
// 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;
}
}
Vous pouvez utiliser l'objet Java.util.Scanner.
public static boolean isNumeric(String inputData) {
Scanner sc = new Scanner(inputData);
return sc.hasNextInt();
}
Vous pouvez utiliser NumberUtils.isCreatable () à partir de Apache Commons Lang .
NumberUtils.isNumber étant obsolète en 4.0, utilisez donc NumberUtils.isCreatable () à la place.
Analysez-le (c'est-à-dire avec Integer#parseInt
) et attrapez simplement l'exception. =)
Pour clarifier: la fonction parseInt vérifie si elle peut analyser le nombre dans tous les cas (évidemment) et si vous voulez quand même analyser le nombre, vous n'allez subir aucune performance en effectuant l'analyse.
Si vous ne voulez pas l’analyser (ou l’analyser très, très rarement), vous voudrez peut-être le faire différemment.
C'est pourquoi j'apprécie l'approche Try * dans .NET. En plus de la méthode traditionnelle Parse semblable à celle de Java, vous disposez également d'une méthode TryParse. Je ne suis pas bon en syntaxe Java (paramètres sortants?), Veuillez donc traiter ce qui suit comme une sorte de pseudo-code Cela devrait cependant clarifier le concept.
boolean parseInteger(String s, out int number)
{
try {
number = Integer.parseInt(myString);
return true;
} catch(NumberFormatException e) {
return false;
}
}
Usage:
int num;
if (parseInteger("23", out num)) {
// Do something with num.
}
J'ai modifié la solution de CraigTP pour accepter la notation scientifique ainsi que les séparateurs décimaux virgule et virgule
^-?\d+([,\.]\d+)?([eE]-?\d+)?$
exemple
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
Java 8 Stream, expression lambda, interface fonctionnelle
Tous les cas traités ( string null, string empty etc )
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();
Vous pouvez utiliser BigDecimal
si la chaîne peut contenir des décimales:
try {
new Java.math.BigInteger(testString);
} catch(NumberFormatException e) {
throw new RuntimeException("Not a valid number");
}
C'est le moyen le plus rapide que je connaisse pour vérifier si String est un nombre ou pas:
public static boolean isNumber(String str){
int i=0, len=str.length();
boolean a=false,b=false,c=false, d=false;
if(i<len && (str.charAt(i)=='+' || str.charAt(i)=='-')) i++;
while( i<len && isDigit(str.charAt(i)) ){ i++; a=true; }
if(i<len && (str.charAt(i)=='.')) i++;
while( i<len && isDigit(str.charAt(i)) ){ i++; b=true; }
if(i<len && (str.charAt(i)=='e' || str.charAt(i)=='E') && (a || b)){ i++; c=true; }
if(i<len && (str.charAt(i)=='+' || str.charAt(i)=='-') && c) i++;
while( i<len && isDigit(str.charAt(i)) ){ i++; d=true;}
return i==len && (a||b) && (!c || (c && d));
}
static boolean isDigit(char c){
return c=='0' || c=='1' || c=='2' || c=='3' || c=='4' || c=='5' || c=='6' || c=='7' || c=='8' || c=='9';
}
Vérification parallèle de très longues chaînes avec IntStream
En Java 8, les tests suivants vérifient si tous les caractères de la variable string
donnée sont compris entre 0 et 9. Notez que la chaîne vide est acceptée:
string.chars().unordered().parallel().allMatch( i -> '0' <= i && '9' >= i )
Sur la base d’autres réponses, j’ai écrit la mienne et elle n’utilise pas de modèles ni d’analyses avec vérification des exceptions.
Il recherche au maximum un signe moins et au maximum une décimale.
Voici quelques exemples et leurs résultats:
"1", "-1", "-1.5" et "-1.556" renvoient true
"1..5", "1A.5", "1.5D", "-" et "--1" retournent faux
Remarque: Si nécessaire, vous pouvez modifier cela pour accepter un paramètre Locale et le transmettre aux appels DecimalFormatSymbols.getInstance () pour utiliser un environnement local spécifique au lieu de l'appel actuel.
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;
}
J'ai illustré certaines conditions pour vérifier les nombres et les décimales sans utiliser aucune API,
Vérifier la longueur du numéro à 1 chiffre
Character.isDigit(char)
Nombre de vérifications correctes (la longueur supposée est 6)
String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");
Vérifiez le nombre de longueurs variables entre (supposons 4 à 6 longueurs)
// {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");
Vérifiez que le nombre décimal de longueur varie entre (supposez une longueur de 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");
J'espère que cela aidera beaucoup de monde.
Si vous utilisez la méthode suivante pour vérifier:
public static boolean isNumeric(String str) {
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
Alors que s'est-il passé avec l'entrée de très longue chaîne, comme j'appelle cette méthode:
System.out.println(isNumeric("94328948243242352525243242524243425452342343948923"));
Le résultat est "true", c'est aussi un nombre trop grand!!. La même chose se produira si vous utilisez regex pour vérifier! Je préfère donc utiliser la méthode "d'analyse" pour vérifier comme ça:
public static boolean isNumeric(String str) {
try {
int number = Integer.parseInt(str);
return true;
} catch (Exception e) {
return false;
}
}
Et le résultat est ce que j'attendais!
Voici deux méthodes qui pourraient fonctionner. (Sans utiliser d'exceptions) . Remarque: Java est une valeur de définition par défaut et la valeur d'une chaîne correspond à l'adresse des données de l'objet de la chaîne . Ainsi, lorsque vous exécutez
stringNumber = stringNumber.replaceAll(" ", "");
Vous avez modifié la valeur d'entrée pour qu'il n'y ait pas d'espaces . Vous pouvez supprimer cette ligne si vous le souhaitez.
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;
}
Voici une autre méthode au cas où vous souhaiteriez autoriser des flottants Cette méthode permettrait apparemment aux nombres du formulaire de passer
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;
}
Je pense que la seule façon de dire de manière fiable si une chaîne est un nombre est de l’analyser. Donc, je voudrais simplement analyser, et si c'est un nombre, vous obtenez le nombre dans un int gratuitement!
Essaye ça:
public boolean isNumber(String str)
{
short count = 0;
char chc[] = {'0','1','2','3','4','5','6','7','8','9','.','-','+'};
for (char c : str.toCharArray())
{
for (int i = 0;i < chc.length;i++)
{
if( c == chc[i]){
count++;
}
}
}
if (count != str.length() )
return false;
else
return true;
}
Si vous souhaitez effectuer la vérification à l'aide d'une expression rationnelle, vous devez créer un objet Pattern statique final, afin que cette expression régulière ne soit compilée qu'une seule fois. La compilation de l'expression rationnelle prend à peu près aussi longtemps que l'exécution de la correspondance. Ainsi, en prenant cette précaution, vous réduirez de moitié le temps d'exécution de la méthode.
final static Pattern NUMBER_PATTERN = Pattern.compile("[+-]?\\d*\\.?\\d+");
static boolean isNumber(String input) {
Matcher m = NUMBER_PATTERN.matcher(input);
return m.matches();
}
Je suppose qu’un nombre est une chaîne ne contenant que des chiffres décimaux, éventuellement un signe + ou - au début et au plus un signe décimal (pas à la fin) et aucun autre caractère autres systèmes de comptage, chiffres romains, hiéroglyphes).
Cette solution est succincte et rapide, mais vous pouvez gagner quelques millisecondes par million d’invocations en procédant ainsi.
static boolean isNumber(String s) {
final int len = s.length();
if (len == 0) {
return false;
}
int dotCount = 0;
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (c < '0' || c > '9') {
if (i == len - 1) {//last character must be digit
return false;
} else if (c == '.') {
if (++dotCount > 1) {
return false;
}
} else if (i != 0 || c != '+' && c != '-') {//+ or - allowed at start
return false;
}
}
}
return true;
}