258 votes

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

J'ai une chaîne de caractères que je charge dans toute mon application et qui passe des chiffres aux lettres, etc. J'ai un simple if pour voir si elle contient des lettres ou des chiffres, mais quelque chose ne fonctionne pas correctement. Voici un extrait.

String text = "abc"; 
String number; 

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

Bien que le text contient des lettres, la condition est retournée comme true . Le et && devrait être évaluée comme les deux conditions devant être true afin de traiter le number = 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 messages sont également valables !

Ce que j'ai utilisé et qui a fonctionné vient 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 votes

Contains ne prend pas une regexp en entrée. Utilisez soit matches("\\d{2,}") ou essayez avec un Pattern y Matcher

0 votes

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

5 votes

Pourquoi vérifiez-vous que text.length() > 2 ? Quelle en est la raison ?

430voto

Adam Liss Points 27815

Si vous traitez le numéro en tant que texte, alors changez :

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 de caractères n'a pas contient des caractères alphabétiques, vérifiez qu'il contient sólo numérique.

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


À titre d'information, il est généralement considéré comme une mauvaise pratique de comparer des valeurs booléennes à des valeurs de type true o false . Il suffit d'utiliser if (condition) o if (!condition) .

39 votes

Vous voudrez probablement ajouter des ancres (par ex. ^[0-9]+$ ) sinon abc123def sera considéré comme un numéro.

14 votes

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.

4 votes

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

26voto

Aman Kumar Gupta Points 229

Afin de vérifier simplement que la chaîne de caractères ne contient que des ALPHABETS, utilisez le code suivant :

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

Afin de vérifier simplement que la chaîne de caractères ne contient que du NUMERO, utilisez le code suivant :

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

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

22voto

tokhi Points 1911

C'est comme ça que je ferais :

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

El $ évitera une correspondance partielle, par exemple 1B .

1 votes

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

0 votes

text.matches("^[0-9]*$") est la même chose que text.matches("[0-9]*") .

20voto

Dhrumil Shah Points 113

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

8 votes

Je ne pense pas que NumberUtil.isCreatable(String str) est correct à utiliser pour ce que la question originale demande. Par exemple, NumberUtil.isCreatable( "09" ) renvoie à false même si "09" ne contient que des chiffres .

1 votes

Même NumberUtils.isCreatable("068907") retournera false

14voto

Anton R Points 151

Performances parseInt et autres sont bien pires que les autres solutions, car elles exigent au moins la gestion des exceptions.

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

Essais de JMH

Les tests comparent les performances de Character.isDigit vs Pattern.matcher().matches vs Long.parseLong par rapport à la vérification des valeurs des caractères.

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

Tests exécutés en mode débit ( Plus c'est grand, mieux c'est ) avec 5 itérations de réchauffement et 5 itérations de test.

Résultats

Notez que parseLong est presque 100 fois plus lent que isDigit pour la première charge d'essai.

## 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évrier 2018

  • Ajoutez deux autres cas - l'un utilisant charAt au lieu de créer un tableau supplémentaire et un autre en utilisant IntStream de codes de caractères
  • Ajout d'une interruption immédiate en cas de non-digit trouvé pour les cas de test en boucle
  • Renvoyer false pour une chaîne vide pour les cas de test bouclés

Mis à jour le 23 février 2018

  • Ajoutez un scénario de test supplémentaire (le plus rapide !) qui compare la valeur d'un caractère sans utiliser le flux.

1 votes

Si vous regardez le code de toCharArray, il alloue un tableau de chars et copie les chars (je pense que cela pourrait être coûteux). Et si vous itériez la chaîne de caractères en utilisant un index et charAt, cela serait-il plus rapide ? Il serait également intéressant d'ajouter la solution d'Andy à vos tests : boolean isNum = text.chars().allMatch(c -> c >= 48 && c <= 57)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X