140 votes

Tester si la chaîne est un entier valide

J'essaie de faire quelque chose d'assez commun : Analyser l'entrée utilisateur dans un shell script. Si l'utilisateur a fourni un entier valide, le script fait une chose, et s'il n'est pas valide, il fait autre chose. Le problème est que je n'ai pas trouvé de moyen facile (et raisonnablement élégant) de faire cela - je ne veux pas avoir à le décortiquer caractère par caractère.

Je sais que cela doit être facile, mais je ne sais pas comment. Je pourrais le faire dans une douzaine de langues, mais pas en BASH !

Dans mes recherches, j'ai trouvé ceci :

Expression régulière permettant de vérifier si une chaîne de caractères est constituée d'un nombre réel valide en base 10

Et il y a une réponse qui parle de regex, mais pour autant que je sache, c'est une fonction disponible en C (entre autres). Néanmoins, il y avait ce qui semblait être une bonne réponse, alors j'ai essayé avec grep, mais grep ne savait pas quoi en faire. J'ai essayé -P qui, sur ma machine, signifie qu'il faut le traiter comme un regexp PERL - rien. Dash E (-E) n'a pas fonctionné non plus. Et -F non plus.

Pour être clair, j'essaie quelque chose comme ça, à la recherche d'un résultat - à partir de là, je modifierai le script pour tirer parti de ce que j'obtiendrai. (En d'autres termes, je m'attendais à ce qu'une entrée non conforme ne renvoie rien alors qu'une ligne valide est répétée).

snafu=$(echo "$2" | grep -E "/^[-+]?(?:\.[0-9]+|(?:0|[1-9][0-9]*)(?:\.[0-9]*)?)$/")
if [ -z "$snafu" ] ;
then
   echo "Not an integer - nothing back from the grep"
else
   echo "Integer."
fi

Quelqu'un pourrait-il illustrer la manière la plus simple de procéder ?

Franchement, c'est un défaut de TEST, à mon avis. Il devrait avoir un drapeau comme celui-ci

if [ -I "string" ] ;
then
   echo "String is a valid integer."
else
   echo "String is not a valid integer."
fi

0voto

Mike Q Points 461

Pour rire, je me suis contenté d'élaborer rapidement un ensemble de fonctions (is_string, is_int, is_float, is alpha string, ou autre), mais il existe des moyens plus efficaces (moins de code) de le faire :

#!/bin/bash

function strindex() {
    x="${1%%$2*}"
    if [[ "$x" = "$1" ]] ;then
        true
    else
        if [ "${#x}" -gt 0 ] ;then
            false
        else
            true
        fi
    fi
}

function is_int() {
    if is_empty "${1}" ;then
        false
        return
    fi
    tmp=$(echo "${1}" | sed 's/[^0-9]*//g')
    if [[ $tmp == "${1}" ]] || [[ "-${tmp}" == "${1}" ]] ; then
        #echo "INT (${1}) tmp=$tmp"
        true
    else
        #echo "NOT INT (${1}) tmp=$tmp"
        false
    fi
}

function is_float() {
    if is_empty "${1}" ;then
        false
        return
    fi
    if ! strindex "${1}" "-" ; then
        false
        return
    fi
    tmp=$(echo "${1}" | sed 's/[^a-z. ]*//g')
    if [[ $tmp =~ "." ]] ; then
        #echo "FLOAT  (${1}) tmp=$tmp"
        true
    else
        #echo "NOT FLOAT  (${1}) tmp=$tmp"
        false
    fi
}

function is_strict_string() {
    if is_empty "${1}" ;then
        false
        return
    fi
    if [[ "${1}" =~ ^[A-Za-z]+$ ]]; then
        #echo "STRICT STRING (${1})"
        true
    else
        #echo "NOT STRICT STRING (${1})"
        false
    fi
}

function is_string() {
    if is_empty "${1}" || is_int "${1}" || is_float "${1}" || is_strict_string "${1}" ;then
        false
        return
    fi
    if [ ! -z "${1}" ] ;then
        true
        return
    fi
    false
}
function is_empty() {
    if [ -z "${1// }" ] ;then
        true
    else
        false
    fi
}

J'ai fait quelques tests ici, j'ai défini que -44 est un int mais que 44- ne l'est pas etc :

for num in "44" "-44" "44-" "4-4" "a4" "4a" ".4" "4.4" "-4.4" "09" "hello" "h3llo!" "!!" " " "" ; do
    if is_int "$num" ;then
        echo "INT = $num"

    elif is_float "$num" ;then
        echo "FLOAT = $num"

    elif is_string "$num" ; then
        echo "STRING = $num"

    elif is_strict_string "$num" ; then
        echo "STRICT STRING = $num"
    else
        echo "OTHER = $num"
    fi
done

Sortie :

INT = 44
INT = -44
STRING = 44-
STRING = 4-4
STRING = a4
STRING = 4a
FLOAT = .4
FLOAT = 4.4
FLOAT = -4.4
INT = 09
STRICT STRING = hello
STRING = h3llo!
STRING = !!
OTHER =  
OTHER = 

REMARQUE : les 0 en tête pourraient être déduits lors de l'addition de nombres tels que l'octal, il est donc préférable de les supprimer si vous avez l'intention de traiter '09' comme un int (ce que je fais) (par ex. expr 09 + 0 ou le dépouiller à l'aide de sed)

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