Vérifier que la chaîne de caractère est un entier

a marqué ce sujet comme résolu.
Auteur du sujet

Bonjour,

Je dois vérifier qu’une chaîne de caractère n’est pas un entier. Or, si j’utilise la fonction parseInt(), la chaîne de caractère 123ABC passe le test (en devenant l’entier 123).

Après plusieurs tests, j’ai eu l’idée d’utiliser cette condition : parseInt(str) == str. Pensez-vous que cela résout mon problème où est-ce qu’il y a des cas que je n’ai pas pris en compte ?

+0 -0

Les fonctions JS sont effectivement parfois un peu surprenantes ^^

Ça ne serait pas une meilleure solution d’écrire « à la main » une fonction pour faire le test en étant sûr du comportement ? C’est assez simple, pour chaque caractère il faut vérifier qu’il ne se trouve pas dans le range '0' à '9'. Si l’un des caractères ne passe pas le test, alors la chaîne ne représente pas un entier, on peut retourner true (n’est pas un entier) de façon anticipée. Si toutes les itérations ont eu lieu et qu’on sort de la boucle, alors c’est que tous les caractères étaient bien dans le range '0' à '9', autrement dit, ça désigne bien un entier : on retourne alors false.

Pour comparer les ranges, tu peux utiliser String.charCodeAt() comme cela :

> '0'.charCodeAt()
48

> '9'.charCodeAt()
57

Le test est donc de savoir, pour chaque caractère c, si son code (c.charCodeAt()) est bien dans l’intervalle inclusif : [48, 57]. Autrement dit, c est un chiffre si c.charCodeAt() est supérieur ou égal à 48 et qu’il est inférieur ou égal à 57.

Le plus simple est de le voir comme ça (équivalent) : c n’est pas un chiffre si son code est strictement inférieur à 48, ou si son code est strictement supérieur à 57 :

if (c.charCodeAt() < 48 || c.charCodeAt() > 57)
    return true; // n'est pas un entier

Tu aurais donc un machin comme ça (pas testé) :

function isNotInteger(cs) {
    for (let c of cs) {
        let code = c.charCodeAt();
        if (code < 48 || code > 57)
            return true; // n'est pas un entier
    }
    return false; // est un entier, tous les caractères sont des chiffres.
}

Édité par sgble

+0 -0

Après plusieurs tests, j’ai eu l’idée d’utiliser cette condition : parseInt(str) == str. Pensez-vous que cela résout mon problème où est-ce qu’il y a des cas que je n’ai pas pris en compte ?

Helmasaur

Ça ne reconnaîtra pas les cas comme +123.

@sgble, De même, ça ne gère pas les + et - en préfixe.

Si tu peux tolérer Infinity et les écritures alternatives (1e3, 0xF), alors tu peux utiliser la fonction isNaN. Si non, le plus rapide est certainement de simplement utiliser une expression régulière.

Petit benchmark:

const doMany = (fn, n) => { for(let i = 0; i < n; i++) { fn(n.toString()) }}

// accepte uniquement des chiffres 0-9 ou -5 (ou, si s est un nombre, également 0xF, 1e10, etc)
const isInt1 = (s) => parseInt(s) == s
// accepte uniquement des chiffres 0-9 ou -5 (ou, si s est un nombre, également 0xF, 1e10, etc)
const isInt2 = (s) => parseInt(s, 10) == s
// accepte uniquement des chiffres 0-9 et 'NaN'
const isInt3 = (s) => parseInt(s, 10).toString() === s
// accepte également Infinity, 0xF, 1e10, +4, -5, etc.
const isInt4 = (s) => !isNaN(s)
// accepte uniquement des chiffres 0-9
const isInt5 = (s) => !!s.match(/^[0-9]+$/)
// accepte uniquement des chiffres 0-9
const isInt6 = (s) => {
  for (let c of s) {
    const code = c.charCodeAt();
    if (code < 48 || code > 57) return false;
  }
  return true;
}

const A = 1e2;
const B = 1e6;
for(let fn of [isInt1, isInt2, isInt3, isInt4, isInt5, isInt6]) {
    let values = [];
    for (let i = 0; i < A; i++) {
    const start = window.performance.now();
    doMany(fn, B);
    values.push(window.performance.now() - start);
  }
  console.log(`${fn.name} - avg ${values.reduce((a, b) => a + b)/values.length}ms / min ${Math.min(...values)}ms / max ${Math.max(...values)}ms`);
}

/*
isInt1 - avg 117.39ms / min 114ms / max 138ms
isInt2 - avg 121.08ms / min 120ms / max 133ms
isInt3 - avg 95.51ms / min 94ms / max 101ms
isInt4 - avg 77.57ms / min 76ms / max 89ms
isInt5 - avg 80.71ms / min 79ms / max 92ms
isInt6 - avg 269.55ms / min 267ms / max 287ms
*/

🕊

+1 -0
Auteur du sujet

Je ne savais pas que j’allais engendrer des réponses aussi exhaustive. Il me semble qu’une chaîne de caractère commençant par un entier passera le test mais si le nombre est au milieu ou à la fin, non.

En fait, c’est pour le paquet que j’utilise pour un lancer de dé. Concernant les expressions régulières, j’ai vu que dans le code source, un nombre entier passe le test.

// TODO: Implement keep/drop
// const VALID_REGEX = /^[0-9d\+\-\/\(\)%fkhdl]*$/;
// const DICE_REGEX = /([0-9]+)?d([0-9]+|%|f)((k|kh|d|dl)([0-9]+))?/g;
const VALID_REGEX = /^[0-9d\+\-\/\(\)%f]*$/;
const DICE_REGEX = /([0-9]+)?d([0-9]+|%|f)/g;

Or, une erreur est retournée. Voici le morceau de code incriminé :

const diceCodes = diceExpression.match(DICE_REGEX);
// […]
for (let diceCode of diceCodes) { /* […] */ }
TypeError: diceCodes is not iterable

Je me suis alors dit que je devrais prendre en charge ce cas particulier en transformant, par exemple 3 en 3d1. J’ai aussi pensé modifier le paquet mais il n’est plus maintenu. La dernière solution serait d’utilisé un paquet plus récent.

Sinon, je vous remercie pour les réponses riches que j’ai reçu. Ça va m’aider dans les cas où je vais devoir faire une vérification. Ça m’a appris pas mal de choses ^^ !

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte