Java String - Voir si une chaîne ne contient que des chiffres et non des lettres


196

J'ai une chaîne que je charge tout au long de mon application, et elle change de chiffres en lettres et autres. J'ai une simple ifdéclaration pour voir si elle contient des lettres ou des chiffres mais, quelque chose ne fonctionne pas tout à fait correctement. Voici un extrait.

String text = "abc"; 
String number; 

if (text.contains("[a-zA-Z]+") == false && text.length() > 2) {
    number = text; 
}

Bien que la textvariable contienne des lettres, la condition retourne comme true. Le et &&doit être évalué comme les deux conditions devant être trueremplies pour traiter lenumber = text;

==============================

Solution:

J'ai pu résoudre ce problème en utilisant le code suivant fourni par un commentaire sur cette question. Tous les autres articles sont également valables!

Ce que j'ai utilisé qui a fonctionné est venu du premier commentaire. Bien que tous les exemples de codes fournis semblent également valables!

String text = "abc"; 
String number; 

if (Pattern.matches("[a-zA-Z]+", text) == false && text.length() > 2) {
    number = text; 
}

5
contient ne prend pas d'expression rationnelle en entrée. Utilisez soit matches("\\d{2,}")ou essayez avec un PatternetMatcher
Guillaume Polet

La chaîne peut-elle avoir une valeur décimale ou uniquement des valeurs entières?
pseudoramble

3
Pourquoi vérifiez-vous text.length ()> 2? Quelle est la raison?
Code Enthusiastic

1
@RedHatcc Pattern.matches("[a-zA-Z]+", text) == falsepeut être simplifié pour!Pattern.matches("[a-zA-Z]+", text)
SARose

2
Utilisation de Java API de streaming sous boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));forme Max MalyshPost.
Yash

Réponses:


354

Si vous allez traiter le numéro sous forme de texte, modifiez:

if (text.contains("[a-zA-Z]+") == false && text.length() > 2){

à:

if (text.matches("[0-9]+") && text.length() > 2) {

Au lieu de vérifier que la chaîne ne contient pas de caractères alphabétiques, vérifiez qu'elle ne contient que chiffres.

Si vous souhaitez réellement utiliser la valeur numérique, utilisez Integer.parseInt()ou Double.parseDouble()comme d'autres l'ont expliqué ci-dessous.


En remarque, il est généralement considéré comme une mauvaise pratique de comparer les valeurs booléennes à trueou false. Utilisez simplement if (condition)ou if (!condition).


25
Vous voudrez probablement ajouter des ancres (par exemple ^[0-9]+$), sinon abc123defsera considéré comme un nombre.
ICR

10
Je ne pense pas que ce soit nécessaire. matches()renvoie vrai si et seulement si c'est une correspondance complète du début à la fin.
Chthonic Project

4
"^ -? \ d + \.? \ d * $" comparera la chaîne entière et ne correspondra que si c'est un nombre valide (négatifs et décimales inclus). Par exemple, il correspondra à 1, 10, 1.0, -1, -1.0, etc. Il correspondra également à "1." mais cela peut souvent être analysé de toute façon.

16
Il n'est pas nécessaire d'appeler && (text.length() > 2). Tout peut être vérifié dans le modèle regex:if (text.matches("[0-9]{3,}")
ctomek

Qu'en est-il des virgules ou des points pour les nombres qui ne sont pas des nombres entiers?
nibbana

20

Vous pouvez également utiliser NumberUtil.isCreatable (String str) depuis Apache Commons


4
Je ne pense pas qu'il NumberUtil.isCreatable(String str)soit correct d'utiliser ce que demande la question d'origine. Par exemple, NumberUtil.isCreatable( "09" )renvoie false, même s'il "09" ne contient que des chiffres .
Abdull

14

Voici comment je le ferais:

if(text.matches("^[0-9]*$") && text.length() > 2){
    //...
}

Le $permettra d'éviter une correspondance partielle, par exemple; 1B.


1
Je n'ai pas besoin de la text.length() > 2pièce, j'ai donc juste remplacé ^[0-9]*$par ^[0-9]+$pour être sûr d'avoir au moins un numéro.
YB Cause

8

Côté performance parseInt et autres sont bien pires que les autres solutions, car elles nécessitent au moins une gestion des exceptions.

J'ai exécuté des tests jmh et j'ai constaté que l'itération sur String en utilisant charAt et en comparant les caractères avec les caractères de limite est le moyen le plus rapide de tester si la chaîne ne contient que des chiffres.

Test JMH

Les tests comparent les performances de Character.isDigitvs Pattern.matcher().matchesvsLong.parseLong vs en vérifiant les valeurs char.

Ces méthodes peuvent produire des résultats différents pour les chaînes non ascii et les chaînes contenant des signes +/-.

Les tests s'exécutent en mode de débit ( plus il vaut mieux, mieux c'est ) avec 5 itérations d'échauffement et 5 itérations de test.

Résultats

Notez que parseLongc'est presque 100 fois plus lent que isDigitpour la première charge de test.

## Test load with 25% valid strings (75% strings contain non-digit symbols)

Benchmark       Mode  Cnt  Score   Error  Units
testIsDigit    thrpt    5  9.275 ± 2.348  ops/s
testPattern    thrpt    5  2.135 ± 0.697  ops/s
testParseLong  thrpt    5  0.166 ± 0.021  ops/s

## Test load with 50% valid strings (50% strings contain non-digit symbols)

Benchmark              Mode  Cnt  Score   Error  Units
testCharBetween       thrpt    5  16.773 ± 0.401  ops/s
testCharAtIsDigit     thrpt    5  8.917 ± 0.767  ops/s
testCharArrayIsDigit  thrpt    5  6.553 ± 0.425  ops/s
testPattern           thrpt    5  1.287 ± 0.057  ops/s
testIntStreamCodes    thrpt    5  0.966 ± 0.051  ops/s
testParseLong         thrpt    5  0.174 ± 0.013  ops/s
testParseInt          thrpt    5  0.078 ± 0.001  ops/s

Suite de tests

@State(Scope.Benchmark)
public class StringIsNumberBenchmark {
    private static final long CYCLES = 1_000_000L;
    private static final String[] STRINGS = {"12345678901","98765432177","58745896328","35741596328", "123456789a1", "1a345678901", "1234567890 "};
    private static final Pattern PATTERN = Pattern.compile("\\d+");

    @Benchmark
    public void testPattern() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = PATTERN.matcher(s).matches();
            }
        }
    }

    @Benchmark
    public void testParseLong() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                try {
                    Long.parseLong(s);
                    b = true;
                } catch (NumberFormatException e) {
                    // no-op
                }
            }
        }
    }

    @Benchmark
    public void testCharArrayIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (char c : s.toCharArray()) {
                    b = Character.isDigit(c);
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testCharAtIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    b = Character.isDigit(s.charAt(j));
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testIntStreamCodes() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = s.chars().allMatch(c -> c > 47 && c < 58);
            }
        }
    }

    @Benchmark
    public void testCharBetween() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    char charr = s.charAt(j);
                    b = '0' <= charr && charr <= '9';
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }
}

Mis à jour le 23 févr.2018

  • Ajoutez deux autres cas - un en utilisant charAtau lieu de créer un tableau supplémentaire et un autre en utilisantIntStream des codes de caractères
  • Ajouter une interruption immédiate si aucun chiffre n'est trouvé pour les cas de test en boucle
  • Renvoie false pour une chaîne vide pour les cas de test en boucle

Mis à jour le 23 févr.2018

  • Ajoutez un autre cas de test (le plus rapide!) Qui compare la valeur char sans utiliser de flux

1
Si vous regardez le code de toCharArray, il alloue un tableau de caractères et copie les caractères (je pense que cela pourrait être coûteux). Qu'en est-il si vous répétez simplement la chaîne à l'aide d'un index et de charAt, serait-ce plus rapide? Serait également intéressant si vous pouviez ajouter la solution d'Andy à vos tests: boolean isNum = text.chars (). AllMatch (c -> c> = 48 && c <= 57)
Aldo Canepa

8

Afin de vérifier simplement la chaîne qu'elle contient uniquement ALPHABETS, utilisez le code suivant:

if (text.matches("[a-zA-Z]+"){
   // your operations
}

Afin de vérifier simplement la chaîne qui ne contient que NUMBER, utilisez le code suivant:

if (text.matches("[0-9]+"){
   // your operations
}

J'espère que cela aidera quelqu'un!


3

boolean isNum = text.chars (). allMatch (c -> c> = 48 && c <= 57)


1
pour réduire les nombres magiques, vous pouvez comparer comme suit:boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
Phe0nix

2

Vous pouvez utiliser Regex.Match

if(text.matches("\\d*")&& text.length() > 2){
    System.out.println("number");
}

Ou vous pouvez utiliser des versions similaires Integer.parseInt(String)ou meilleures Long.parseLong(String)pour de plus grands nombres comme par exemple:

private boolean onlyContainsNumbers(String text) {
    try {
        Long.parseLong(text);
        return true;
    } catch (NumberFormatException ex) {
        return false;
    }
} 

Et puis testez avec:

if (onlyContainsNumbers(text) && text.length() > 2) {
    // do Stuff
}

.matches ("^ \\ d + $")
CrandellWS

2

Les expressions rationnelles ci-dessous peuvent être utilisées pour vérifier si une chaîne n'a qu'un nombre ou non:

if (str.matches(".*[^0-9].*")) or if (str.matches(".*\\D.*"))

Les deux conditions ci-dessus seront truerenvoyées si String contient des non-nombres. Activé false, la chaîne n'a que des chiffres.


2

Apache Commons Lang fournit org.apache.commons.lang.StringUtils.isNumeric(CharSequence cs), qui prend comme argument a Stringet vérifie s'il se compose de caractères purement numériques (y compris des nombres provenant de scripts non latins). Cette méthode renvoiefalse s'il existe des caractères tels que l'espace, le moins, le plus et les séparateurs décimaux tels que la virgule et le point.

D'autres méthodes de cette classe permettent d'autres vérifications numériques.


1
Cela devrait être beaucoup plus rapide qu'un regex; voici l'implémentation: public static boolean isNumeric(String str) { if (str == null) { return false; } else { int sz = str.length(); for(int i = 0; i < sz; ++i) { if (!Character.isDigit(str.charAt(i))) { return false; } } return true; } }
Leo

1

Il existe de nombreuses fonctionnalités pour obtenir des numéros de Strings en Java (et vice versa). Vous voudrez peut-être ignorer la partie regex pour vous éviter la complication de cela.

Par exemple, vous pouvez essayer de voir ce qui vous Double.parseDouble(String s)rapporte. Il doit lancer un NumberFormatExceptions'il ne trouve pas de valeur appropriée dans la chaîne. Je suggérerais cette technique car vous pourriez réellement utiliser la valeur représentée par le Stringcomme un type numérique.


5
L'utilisation d'une exception comme raison de tester votre entrée peut être une mauvaise idée, les exceptions créent une surcharge importante.
Ofir Luzon

1
@OfirLuzon Je conviens que les exceptions ne sont pas un excellent moyen de gérer les cas attendus qui vont se produire. Cependant, je pense qu'il est difficile de dire s'il y aurait un impact sur les performances sans plus de contexte.
pseudoramble

1

Voici mon code, j'espère que cela vous aidera!

 public boolean isDigitOnly(String text){

    boolean isDigit = false;

    if (text.matches("[0-9]+") && text.length() > 2) {
        isDigit = true;
    }else {
        isDigit = false;
    }

    return isDigit;
}

0

Ce code est déjà écrit. Si cela ne vous dérange pas le coup de performance (extrêmement) mineur - qui n'est probablement pas pire que de faire une correspondance regex - utilisez Integer.parseInt () ou Double.parseDouble () . Cela vous dira tout de suite si une chaîne n'est que des nombres (ou est un nombre, selon le cas). Si vous devez gérer des chaînes de nombres plus longues, les constructeurs sportifs BigInteger et BigDecimal qui acceptent les chaînes. N'importe lequel de ces éléments générera une exception NumberFormatException si vous essayez de lui transmettre un non-nombre (intégral ou décimal, basé sur celui que vous choisissez, bien sûr). Alternativement, selon vos besoins, il suffit d'itérer les caractères dans la chaîne et de vérifier Character.isDigit ()et / ou Character.isLetter () .


0
import java.util.*;

class Class1 {
    public static void main(String[] argh) {
        boolean ans = CheckNumbers("123");
        if (ans == true) {
            System.out.println("String contains numbers only");
        } else {
            System.out.println("String contains other values as well");

        }
    }


    public static boolean CheckNumbers(String input) {
        for (int ctr = 0; ctr < input.length(); ctr++) {
            if ("1234567890".contains(Character.valueOf(input.charAt(ctr)).toString())) {
                continue;
            } else {
                return false;
            }
        }
        return true;
    }
}

0
Character first_letter_or_number = query.charAt(0);
                //------------------------------------------------------------------------------
                if (Character.isDigit())
                {

                }
                else if (Character.isLetter())
                {

                }

0

Exemple de test de travail

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

public class PaserNo {

    public static void main(String args[]) {

        String text = "gg";

        if (!StringUtils.isBlank(text)) {
            if (stringContainsNumber(text)) {
                int no=Integer.parseInt(text.trim());
                System.out.println("inside"+no);

            } else {
                System.out.println("Outside");
            }
        }
        System.out.println("Done");
    }

    public static boolean stringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }
}

Votre code peut toujours être cassé par "1a", etc., vous devez donc vérifier l'exception

if (!StringUtils.isBlank(studentNbr)) {
                try{
                    if (isStringContainsNumber(studentNbr)){
                    _account.setStudentNbr(Integer.parseInt(studentNbr.trim()));
                }
                }catch(Exception e){
                    e.printStackTrace();
                    logger.info("Exception during parse studentNbr"+e.getMessage());
                }
            }

Méthode pour vérifier que non est une chaîne ou non

private boolean isStringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }

0

C'est une mauvaise pratique d'impliquer toute exception de levée / manipulation dans un scénario aussi typique.

Par conséquent , un parseInt () n'est pas agréable, mais une expression régulière est une solution élégante pour cela, mais prendre soin de ce qui suit:
-fractions
numéros séronégatifs
séparateur -decimal peut différer contries ( « » par exemple « » ou)
-Parfois il est permis d'avoir un soi-disant séparateur de milliers, comme un espace ou une virgule, par exemple 12.324.1000.355

Pour gérer tous les cas nécessaires dans votre application, vous devez être prudent, mais cette expression régulière couvre les scénarios typiques (positifs / négatifs et fractionnaires, séparés par un point): ^ [- +]? \ D *.? \ D + $
For test, je recommande regexr.com .


0

Version légèrement modifiée d'Adam Bodrogi:

public class NumericStr {


public static void main(String[] args) {
    System.out.println("Matches: "+NumericStr.isNumeric("20"));         // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("20,00"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30,000.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("-2980"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("$20"));            // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("jdl"));            // Should be false
    System.out.println("Matches: "+NumericStr.isNumeric("2lk0"));           // Should be false
}

public static boolean isNumeric(String stringVal) {
    if (stringVal.matches("^[\\$]?[-+]?[\\d\\.,]*[\\.,]?\\d+$")) {
        return true;
    }

    return false;
}
}

J'ai dû utiliser cela aujourd'hui, alors je viens de publier mes modifications. Comprend la devise, la virgule des milliers ou la notation de période, et certaines validations. N'inclut pas les autres notations monétaires (euro, cent), les virgules de vérification sont tous les trois chiffres.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.