Vérifiez si une chaîne est analysable dans Long sans essayer?

Long.parseLong("ssortingng") génère une erreur si la chaîne n’est pas analysable en long. Existe-t-il un moyen de valider la chaîne plus rapidement que d’utiliser try-catch ? Merci

Vous pouvez créer une expression régulière assez complexe, mais cela ne vaut pas la peine. Utiliser des exceptions ici est absolument normal.

C’est naturel situation exceptionnelle: vous supposez qu’il y a un entier dans la chaîne mais en effet il y a autre chose. L’exception doit être lancée et gérée correctement.

Si vous regardez à l’intérieur parseLong code parseLong , vous verrez qu’il y a beaucoup de vérifications et d’opérations différentes. Si vous voulez faire tout cela avant d’parsingr, cela diminuera les performances (si nous parlons d’parsingr des millions de nombres, sinon cela n’a pas d’importance). Ainsi, la seule chose que vous pouvez faire si vous avez vraiment besoin d’améliorer les performances en évitant les exceptions est de copier l’implémentation de parseLong dans votre propre fonction et de renvoyer NaN au lieu de générer des exceptions dans tous les cas correspondants.

De commons-lang SsortingngUtils:

 public static boolean isNumeric(Ssortingng str) { if (str == null) { return false; } int sz = str.length(); for (int i = 0; i < sz; i++) { if (Character.isDigit(str.charAt(i)) == false) { return false; } } return true; } 

Vous pourriez faire quelque chose comme

 if(s.matches("\\d*")){ } 

Utiliser l’expression régulière – pour vérifier si Ssortingng est plein de chiffres. Mais qu’est-ce que vous avez à gagner? une autre si condition?

Vous pouvez utiliser java.util.Scanner

 Scanner sc = new Scanner(s); if (sc.hasNextLong()) { long num = sc.nextLong(); } 

Ceci vérifie également la scope, etc. Bien sûr, il sera dit que "99 bottles of beer" hasNextLong() , donc si vous voulez vous assurer que ce ne soit que long vous devrez faire des vérifications supplémentaires.

Ceci est une question valable car il est parfois nécessaire d’inférer le type de données représenté dans une chaîne. Par exemple, vous devrez peut-être importer un grand CSV dans une firebase database et représenter les types de données avec précision. Dans de tels cas, appeler Long.parseLong et intercepter une exception peut être trop lent.

Le code suivant ne gère que les décimales ASCII:

 public class LongParser { // Since tryParseLong represents the value as negative during processing, we // counter-intuitively want to keep the sign if the result is negative and // negate it if it is positive. private static final int MULTIPLIER_FOR_NEGATIVE_RESULT = 1; private static final int MULTIPLIER_FOR_POSITIVE_RESULT = -1; private static final int FIRST_CHARACTER_POSITION = 0; private static final int SECOND_CHARACTER_POSITION = 1; private static final char NEGATIVE_SIGN_CHARACTER = '-'; private static final char POSITIVE_SIGN_CHARACTER = '+'; private static final int DIGIT_MAX_VALUE = 9; private static final int DIGIT_MIN_VALUE = 0; private static final char ZERO_CHARACTER = '0'; private static final int RADIX = 10; /** * Parses a ssortingng representation of a long significantly faster than * Long.ParseLong, and avoids the noteworthy overhead of * throwing an exception on failure. Based on the parseInt code from * http://nadeausoftware.com/articles/2009/08/java_tip_how_parse_integers_quickly * * @param ssortingngToParse * The ssortingng to try to parse as a long. * * @return the boxed long value if the ssortingng was a valid * representation of a long; otherwise null. */ public static Long tryParseLong(final Ssortingng ssortingngToParse) { if (ssortingngToParse == null || ssortingngToParse.isEmpty()) { return null; } final int inputSsortingngLength = ssortingngToParse.length(); long value = 0; /* * The absolute value of Long.MIN_VALUE is greater than the absolute * value of Long.MAX_VALUE, so during processing we'll use a negative * value, then we'll multiply it by signMultiplier before returning it. * This allows us to avoid a conditional add/subtract inside the loop. */ int signMultiplier = MULTIPLIER_FOR_POSITIVE_RESULT; // Get the first character. char firstCharacter = ssortingngToParse.charAt(FIRST_CHARACTER_POSITION); if (firstCharacter == NEGATIVE_SIGN_CHARACTER) { // The first character is a negative sign. if (inputSsortingngLength == 1) { // There are no digits. // The ssortingng is not a valid representation of a long value. return null; } signMultiplier = MULTIPLIER_FOR_NEGATIVE_RESULT; } else if (firstCharacter == POSITIVE_SIGN_CHARACTER) { // The first character is a positive sign. if (inputSsortingngLength == 1) { // There are no digits. // The ssortingng is not a valid representation of a long value. return null; } } else { // Store the (negative) digit (although we aren't sure yet if it's // actually a digit). value = -(firstCharacter - ZERO_CHARACTER); if (value > DIGIT_MIN_VALUE || value < -DIGIT_MAX_VALUE) { // The first character is not a digit (or a negative sign). // The string is not a valid representation of a long value. return null; } } // Establish the "maximum" value (actually minimum since we're working // with negatives). final long rangeLimit = (signMultiplier == MULTIPLIER_FOR_POSITIVE_RESULT) ? -Long.MAX_VALUE : Long.MIN_VALUE; // Capture the maximum value that we can multiply by the radix without // overflowing. final long maxLongNegatedPriorToMultiplyingByRadix = rangeLimit / RADIX; for (int currentCharacterPosition = SECOND_CHARACTER_POSITION; currentCharacterPosition < inputStringLength; currentCharacterPosition++) { // Get the current digit (although we aren't sure yet if it's // actually a digit). long digit = stringToParse.charAt(currentCharacterPosition) - ZERO_CHARACTER; if (digit < DIGIT_MIN_VALUE || digit > DIGIT_MAX_VALUE) { // The current character is not a digit. // The ssortingng is not a valid representation of a long value. return null; } if (value < maxLongNegatedPriorToMultiplyingByRadix) { // The value will be out of range if we multiply by the radix. // The string is not a valid representation of a long value. return null; } // Multiply by the radix to slide all the previously parsed digits. value *= RADIX; if (value < (rangeLimit + digit)) { // The value would be out of range if we "added" the current // digit. return null; } // "Add" the digit to the value. value -= digit; } // Return the value (adjusting the sign if needed). return value * signMultiplier; } } 

org.apache.commons.lang3.math.NumberUtils.isParsable (yourSsortingng) déterminera si la chaîne peut être analysée par l’un des suivants: Integer.parseInt (Ssortingng), Long.parseLong (Ssortingng), Float.parseFloat (Ssortingng) ou Double .parseDouble (Ssortingng)

Comme vous êtes intéressé par les Longs, vous pouvez avoir une condition qui vérifie isParsable et ne contient pas de décimale

 if (NumberUtils.isParsable(yourSsortingng) && !SsortingngUtils.contains(yourSsortingng,".")){ ... 

Ce cas est courant pour les formulaires et les programmes où vous avez le champ de saisie et vous ne savez pas si la chaîne est un nombre valide. L’utilisation de try / catch avec votre fonction java est la meilleure chose à faire si vous comprenez le fonctionnement de try / catch par rapport à la tentative d’écriture de la fonction vous-même. Pour configurer le bloc try catch dans la machine virtuelle .NET, il n’y a aucune instruction de surcharge, et c’est probablement la même chose en Java. S’il y a des instructions utilisées au mot-clé try, celles-ci seront minimales, et l’essentiel des instructions sera utilisé dans la partie catch et cela ne se produit que dans les rares cas où le nombre n’est pas valide.

Donc, même s’il semble que vous puissiez vous-même écrire une fonction plus rapide, vous devrez l’optimiser davantage que le compilateur Java afin de battre le mécanisme try / catch que vous utilisez déjà, et les avantages d’une fonction plus optimisée être très minimal car l’parsing des nombres est assez générique.

Si vous exécutez des tests de synchronisation avec votre compilateur et le mécanisme de capture de Java que vous avez déjà décrit, vous ne remarquerez probablement aucun ralentissement marginal au-dessus, et par marginal je veux dire qu’il ne devrait presque rien y avoir.

Obtenez la spécification du langage Java pour mieux comprendre les exceptions et vous verrez que l’utilisation d’une telle technique dans ce cas est parfaitement acceptable car elle encapsule une fonction assez grande et complexe. L’ajout de ces quelques instructions supplémentaires dans le CPU pour la partie d’essai ne va pas être un gros problème.

Je pense que c’est la seule façon de vérifier si une chaîne est une valeur longue valide. mais vous pouvez vous implémenter une méthode pour y parvenir, en ayant en tête la plus grande valeur à long terme.

Il existe des moyens beaucoup plus rapides d’ parsingr un long que Long.parseLong . Si vous voulez voir un exemple d’une méthode qui n’est pas optimisée, alors vous devriez regarder parseLong 🙂

Devez-vous vraiment prendre en compte les “chiffres” non-ASCII?

Avez-vous vraiment besoin de passer plusieurs appels de méthodes autour d’une base, même si vous êtes probablement en train d’parsingr la base 10?

🙂

Utiliser une expression rationnelle n’est pas la solution: il est plus difficile de déterminer si votre nombre est trop long: comment utiliser une expression rationnelle pour déterminer que 9223372036854775807 peut être analysé sur une longue période, mais que 9223372036854775907 ne le peut pas?

Cela dit, la réponse à une méthode d’parsing syntaxique longue et rapide est une machine à états et que vous vouliez tester si elle est analysable ou non. Simplement, ce n’est pas une machine à états générique acceptant des expressions rationnelles complexes mais une application codée en dur.

Je peux tous les deux écrire une méthode qui parsing un long et un autre qui détermine si un long peut être analysé qui surpasse totalement Long.parseLong () .

Maintenant que veux-tu? Une méthode de test d’état? Dans ce cas, une méthode de test d’état peut ne pas être souhaitable si vous souhaitez éviter de calculer deux fois plus longtemps.

Enveloppez simplement votre appel dans un try / catch.

Et si vous voulez vraiment quelque chose de plus rapide que le par défaut Long.parseLong, écrivez-en un qui soit adapté à votre problème: base 10 si vous êtes en base 10, ne pas vérifier les chiffres en dehors de l’ASCII -yon-go etc.).

J’espère que cela aide avec les valeurs positives. J’ai utilisé cette méthode une fois pour valider les clés primaires de la firebase database.

 private static final int MAX_LONG_STR_LEN = Long.toSsortingng(Long.MAX_VALUE).length(); public static boolean validId(final CharSequence id) { //avoid null if (id == null) { return false; } int len = id.length(); //avoid empty or oversize if (len < 1 || len > MAX_LONG_STR_LEN) { return false; } long result = 0; // ASCII '0' at position 48 int digit = id.charAt(0) - 48; //first char cannot be '0' in my "id" case if (digit < 1 || digit > 9) { return false; } else { result += digit; } //start from 1, we already did the 0. for (int i = 1; i < len; i++) { // ASCII '0' at position 48 digit = id.charAt(i) - 48; //only numbers if (digit < 0 || digit > 9) { return false; } result *= 10; result += digit; //if we hit 0x7fffffffffffffff // we are at 0x8000000000000000 + digit - 1 // so negative if (result < 0) { //overflow return false; } } return true; } 

Essayez d’utiliser cette expression régulière:

^(-9223372036854775808|0)$|^((-?)((?!0)\d{1,18}|[1-8]\d{18}|9[0-1]\d{17}|92[0-1]\d{16}|922[0-2]\d{15}|9223[0-2]\d{14}|92233[0-6]\d{13}|922337[0-1]\d{12}|92233720[0-2]\d{10}|922337203[0-5]\d{9}|9223372036[0-7]\d{8}|92233720368[0-4]\d{7}|922337203685[0-3]\d{6}|9223372036854[0-6]\d{5}|92233720368547[0-6]\d{4}|922337203685477[0-4]\d{3}|9223372036854775[0-7]\d{2}|922337203685477580[0-7]))$

Il vérifie tous les nombres possibles pour Long. Mais comme vous le savez dans Java Long peut contenir des symboles supplémentaires comme + , L , _ et etc. Et cette expression rationnelle ne valide pas ces valeurs. Mais si cette expression rationnelle ne vous suffit pas, vous pouvez append des ressortingctions supplémentaires.

Vous pouvez essayer d’utiliser une expression régulière pour vérifier la forme de la chaîne avant d’essayer de l’parsingr?