Como verificar se uma string é int, mas não dupla, etc.?

155

O PHP possui uma intval()função que converterá uma string em um número inteiro. No entanto, quero verificar se a string é um número inteiro de antemão, para que eu possa dar uma mensagem de erro útil ao usuário, se estiver errada. O PHP possui is_int(), mas isso retorna false para strings como "2".

O PHP tem a is_numeric()função, mas isso retornará true se o número for um dobro. Eu quero algo que retorne falso para um duplo, mas verdadeiro para um int.

por exemplo:

my_is_int("2") == TRUE
my_is_int("2.1") == FALSE
Rory
fonte
6
como deve ser tratado o "2.0"?
nickf

Respostas:

183

Que tal usar ctype_digit?

Do manual:

<?php
$strings = array('1820.20', '10002', 'wsl!12');
foreach ($strings as $testcase) {
    if (ctype_digit($testcase)) {
        echo "The string $testcase consists of all digits.\n";
    } else {
        echo "The string $testcase does not consist of all digits.\n";
    }
}
?>

O exemplo acima apresentará:

A cadeia 1820.20 não consiste em todos os dígitos.
A sequência 10002 consiste em todos os dígitos.
A cadeia wsl! 12 não consiste em todos os dígitos.

Isso funcionará apenas se sua entrada for sempre uma string:

$numeric_string = '42';
$integer        = 42;

ctype_digit($numeric_string);  // true
ctype_digit($integer);         // false

Se sua entrada for do tipo int, combine ctype_digitcom is_int.

Se você se importa com números negativos, precisará verificar a entrada para obter uma precedente -e, se for o caso, chamar ctype_digituma substrda sequência de entrada. Algo assim faria:

function my_is_int($input) {
  if ($input[0] == '-') {
    return ctype_digit(substr($input, 1));
  }
  return ctype_digit($input);
}
Dominic Rodger
fonte
7
números negativos?
Anurag
1
@ Anurag, editado em (embora se você realmente se importa com isso, um regex é provavelmente mais simples).
Dominic Rodger
4
Se você deseja verificar números inteiros negativos, adicione o uso de abs () assim em ctype_digit(abs($str))vez de apenas ctype_digit.
precisa
3
@enchance abs('definitelynotanint') === 0. além disso, ctype_digitleva apenas seqüências de caracteres
Klesun 8/16
Isso não está correto. Um número inteiro grande em PHP é um duplo!
Jgmjgm 11/11
91

filter_var deve fazê-lo:

var_dump(filter_var('2', FILTER_VALIDATE_INT));   // 2
var_dump(filter_var('2.0', FILTER_VALIDATE_INT)); // false
var_dump(filter_var('2.1', FILTER_VALIDATE_INT)); // false

mas

var_dump(filter_var(2, FILTER_VALIDATE_INT));     // 2
var_dump(filter_var(2.0, FILTER_VALIDATE_INT));   // 2
var_dump(filter_var(2.1, FILTER_VALIDATE_INT));   // false

Se você deseja apenas os booleanos como valores de retorno, envolva-os em uma função, por exemplo

function validatesAsInt($number)
{
    $number = filter_var($number, FILTER_VALIDATE_INT);
    return ($number !== FALSE);
}
Gordon
fonte
2
Gosto da maioria das respostas, mas acho que essa é a mais elegante.
Ian Dunn
6
@grenoult 3v4l.org/qVRRS fornece int 0 para seqüências de caracteres e números inteiros; portanto, não sei por que você acha que isso não funciona. Você está comparando o resultado com ==talvez?
Gordon
1
@Gordon meu erro, eu estava realmente comparando apenas com um if 3v4l.org/IAvCF
Guillaume Renoult
Isso fará algumas coisas estranhas, como return true para "+123". É atenuado que ele devolve o int verdadeiro, mas ainda pode não ser o que as pessoas querem, o que é uma verificação estrita do int.
Jgmjgm
@ MohammedRédaOUASSINI o OP pediu para validar strings , não floats. Ele vai funcionar se você passar em '-1.0' (uma string), será não trabalho se você passar em -1.0 (um float), mas isso não era um requisito para começar. Veja 3v4l.org/bOX6X
Gordon em
20

+1 na resposta de Dominic (usando ctype_digit). Outra maneira de fazer isso é com coerção de tipo:

$inty = "2";
$inty2 = " 2";
$floaty = "2.1";
$floaty2 = "2.0";

is_int($inty + 0); // true
is_int($floaty + 0); // false
is_int($floaty2 + 0); // false

// here's difference between this and the ctype functions.
is_int($inty2 + 0);  // true
ctype_digit($inty2); // false
nickf
fonte
2
+1 para você também (embora eu queira saber se esse caso específico seria tratado com mais clareza aparando a sequência de entrada).
precisa saber é o seguinte
6
Este método não funciona para cordas não numéricos: is_int ( "abc" +0) é verdade
Kai Pommerenke
1
É verdade, ele não funciona para strings não numéricos ... que sobre is_int($inty + 0) && is_numeric($inty)(eu sei que é uma solução preguiçoso, mas obras para a maioria das intenções e propósitos ...
Alex Mantaut
O uso de jugging de tipo resultará em uma verificação bastante flexível, onde as ints podem ser representadas de todos os tipos de formas de string, não é uma verificação de string. Você também não precisa +0. Você pode simplesmente + $ var.
Jgmjgm
13

Faça a conversão para int. se ainda tiver o mesmo valor, int;

function my_is_int($var) {
  $tmp = (int) $var;
  if($tmp == $var)
       return true;
  else
       return false;
}
greg
fonte
2
Ou ainda mais curto:return $var == (int) $var;
Al.G.
1
@ AI.G. O que acontece se o elenco falhar
DR.
Isso é muito próximo, deve evitar malabarismos de tipo, se não for necessário. Isso funcionará se $ var for "123xxxx".
Jgmjgm 11/12
8
/**
 * Check if a number is a counting number by checking if it
 * is an integer primitive type, or if the string represents
 * an integer as a string
 */
function is_int_val($data) {
    if (is_int($data) === true) return true;
    if (is_string($data) === true && is_numeric($data) === true) {
        return (strpos($data, '.') === false);
    }
}

Fonte .

GmonC
fonte
ao invés de espalhar meu código com poucas funções utilitárias, prefiro ter algo embutido no php.
Rory
Também não gosto desses hacks. Mas, usando essa abordagem ou sugestão de tipo de Dominic, você encapsulará toda a implementação de qualquer maneira em um método. Ao usar php, sempre tenho uma classe "Util" para resolver esses problemas.
GmonC
elseifpode ser apenas ifporque você já retornou na declaração acima.
precisa saber é o seguinte
Também não há necessidade de retornar false no final.
precisa saber é o seguinte
1
Se $datafor um objeto, isso retornará null. Melhor ter return false;o final.
Theodore R. Smith
6

Tinha uma necessidade de um robusto is_intrecentemente. Achei intval () imprevisível demais:

intval(array('foo', 'bar')) //returns 1 ?!?
intval("2dog") //returns 2 even though the value is definitely not an integer
intval("dog2") //also returns 2


Me deparei com esse trecho nos comentários da documentação do PHP e, após testá-lo, ele cobre quase tudo o que você lança nele:

function my_is_int($s) {
    return (is_numeric($s) ? intval($s) == $s : false);
}


my_is_int(2); //true
my_is_int("2"); //true
my_is_int(2.1); //false
my_is_int("2.1"); //false
my_is_int("dog"); //false
my_is_int("2dog"); //false
my_is_int("dog2"); //false
my_is_int(array('foo', 'bar')); //false
my_is_int(array(1)); //false


Mas cuidado:

my_is_int(2.0); //true
my_is_int("2.0"); //true
Costa
fonte
6

Uma maneira realmente limpa que eu gosto de usar é essa. Você o lança duas vezes, primeiro int, segundo stringe depois faz uma comparação rigorosa ===. Veja o exemplo abaixo:

$value === (string)(int)$value;

Agora, sobre sua função my_is_int, você pode fazer algo assim:

function my_is_int($value){ return $value === (string)(int)$value; }
my_is_int('2');  // true
my_is_int('2.1') // false
Jonathan Gagne
fonte
4
function my_is_int($var) {
    return preg_match('/^\d+$/', $var);
}
Michael Connor
fonte
1
Usei uma variação disso, permitindo o sinal numérico:'/^[-+]?[0-9]+$/'
Denilson Sá Maia
É o mesmo que ctype_digit, mas também permite uma nova linha à direita.
Jgmjgm
3

Estou usando este:

function isInt($val){

    return (filter_var($val, FILTER_VALIDATE_INT) !== false && strpos($val, '-') === false);

}

var_dump (isInt("1"));
julesdude
fonte
3

Você pode apenas verificar se há um número, se for então verificar que o vazamento recebe um dobro ou não:

((is_numeric($var) && !is_double(1*$var)));

Apenas para números positivos:

(is_numeric($var) && !is_double(1*$var)) && ($var >= 0)

Verificando:

$numbersToCheck = array("a", "-1", "1", "1.0", "1.2");

foreach ($numbersToCheck as $var) {
    echo $var . " is integer? ";var_dump((is_numeric($var) && !is_double(1*$var)));

    echo $var . " is a positive integer? ";var_dump((is_numeric($var) && !is_double(1*$var)) && ($var >= 0));
}

Resultado:

a is integer? bool(false)
a is a positive integer? bool(false)
-1 is integer? bool(true)
-1 is a positive integer? bool(false)
1 is integer? bool(true)
1 is a positive integer? bool(true)
1.0 is integer? bool(false)
1.0 is a positive integer? bool(false)
1.2 is integer? bool(false)
1.2 is a positive integer? bool(false)
Jordi Martínez
fonte
is_numeric () era o que eu estava procurando.
Ccjjmartin
1
Para ter certeza de que é isso que você deseja, você precisará ler a fonte PHP, pois ela não está bem documentada. Por exemplo, is_numeric aceita espaços em branco à esquerda, o que não é algo documentado no manual do PHP. Você também deve ter em mente que números inteiros de seqüência de caracteres que são muito grandes para serem representados com um int nativo são convertidos para flutuar.
jgmjgm
2

Tente o seguinte:

$string='12abc';
if ((int)$string==$string) var_dump((int)$string); else echo 'Invalid!';
// Outputs: Invalid!

$string='789';
if ((int)$string==$string) var_dump((int)$string); else echo 'Invalid!';
// Outputs: int 789

$string='345.00';
if ((int)$string==$string) var_dump((int)$string); else echo 'Invalid!';
// Outputs: 345

$string='123.01';
if ((int)$string==$string) var_dump((int)$string); else echo 'Invalid!';
// Outputs: Invalid!

Também funciona se a sua string $ tiver casas decimais

Jack M.
fonte
Isso tratará 123xxxx como uma sequência int válida.
Jgmjgm 11/11
2

Isso cuidará do número negativo também

function myIsInt()
{
   return (is_numeric($var) AND (is_int($var) OR ctype_digit(trim($var, '-'))))
}
//'234-' => false
//'-234' => true
//'--234' => false
//'234' => true
wolakpaul
fonte
Não entendo por que isso retornaria falso para 234- ou --234, você testou? Isso retornará verdadeiro para ----- 1234 ----
jgmjgm
2
function my_is_int($var){
    return is_numeric($var) && gettype($var+0)=='integer';
}
conceder sol
fonte
2

Eu inventei uma maneira que não consegui encontrar em lugar nenhum, então estou colocando aqui:

Sem mais delongas, é o seguinte: ctype_digit((string) abs($input))

Exemplo:

function means_int($input) {
    return ctype_digit((string) abs($input));
}

$list = array(
    0,
    '0',
    1,
    '1',
    1.1,
    '1.1',
    2.0,
    '2.0',  
    2.6,
    '2.6',
    -4,
    '-4',   
    -3.2,
    '-3.2',
    -30.02,
    '-30.02',   
    100.00,
    '100.00',   
);

foreach ($list as $x) {
    var_dump($x);
    var_dump(means_int($x));
    echo PHP_EOL;
}

Resultados: (são como esperado, suponho)

int(0)
bool(true)

string(1) "0"
bool(true)

int(1)
bool(true)

string(1) "1"
bool(true)

float(1.1)
bool(false)

string(3) "1.1"
bool(false)

float(2)
bool(true)

string(3) "2.0"
bool(true)

float(2.6)
bool(false)

string(3) "2.6"
bool(false)

int(-4)
bool(true)

string(2) "-4"
bool(true)

float(-3.2)
bool(false)

string(4) "-3.2"
bool(false)

float(-30.02)
bool(false)

string(6) "-30.02"
bool(false)

float(100)
bool(true)

string(6) "100.00"
bool(true)
Smuuf
fonte
abs está lançando entrada da string para numérico. É o mesmo que is_int (+ $ var).
Jgmjgm
2

Talvez não seja a maneira mais eficiente de fazer isso. Mas você pode escrever em uma linha.

function my_is_int($input) {
    return intval($input).'' === $input.'';
}

Como esperado:

    my_is_int(1);     // TRUE
    my_is_int(-1);    // TRUE
    my_is_int(1.2);   // FALSE
    my_is_int("1");   // TRUE
    my_is_int("-1");  // TRUE
    my_is_int("1.2"); // FALSE
    my_is_int(0);     // TRUE
    my_is_int(null);  // FALSE

Peguei vocês:

    my_is_int(1.0);   // TRUE
    my_is_int("1.0"); // FALSE
mwallisch
fonte
Este está correto, desde que você garanta que $ input seja do tipo string.
Jgmjgm
2

Alguns anos atrasado, mas com base nas respostas dadas aqui, encontrei uma solução um pouco mais precisa (em booleanos, em particular) e mais eficiente (acho) do que a maioria das outras respostas:

function my_is_int($s) {
    return ctype_digit($s) || is_int($s);
}

Trabalhando conforme o esperado para estes:

my_is_int(2);                   // true
my_is_int("2");                 // true
my_is_int(-2);                  // true
my_is_int(2.0);                 // false
my_is_int("2.0");               // false
my_is_int(2.1);                 // false
my_is_int("2.1");               // false
my_is_int("dog");               // false
my_is_int("2dog");              // false
my_is_int("dog2");              // false
my_is_int(array('foo', 'bar')); // false
my_is_int(array(1));            // false
my_is_int(true);                // false
my_is_int(false);               // false
my_is_int("true");              // false
my_is_int("false");             // false
my_is_int("0x101010");          // false

Exceto, talvez, estes 2:

my_is_int(0x101010);            // true
my_is_int("-2");                // false
SharkWipf
fonte
muito agradável. se você quiser manipular a sequência numérica com sinal negativo, poderá mudar para ctype_digits (preg_replace ('/ ^ - /', '', $ s)), embora isso comece a ficar um pouco longo. Além disso, 0x101010 é um int, portanto, isso não é um erro, mas "0x101010" pode ser considerado incorreto e tenho certeza de que as seqüências binárias correspondentes à notação literal binária ("0b11111") também falhariam
fbas
1

E se:

function isIntStr($str) {
   return preg_match('/^(-?\d+)(?:\.0+)?$/', trim($str), $ms)
       && bcComp($ms[1], PHP_INT_MAX) <= 0
       && bcComp($ms[1], -PHP_INT_MAX - 1) >= 0;
}

Esta função só deve retornar true para qualquer número de string que possa ser convertido para int com (int)ou intval()sem perder nada de significado matemático (como zeros após ponto decimal ou números fora do intervalo inteiro do PHP) enquanto aceita coisas que não são matematicamente significativas (como espaço em branco; zeros à esquerda) ou, após o ponto decimal, zeros exclusivamente).

Retornará false para, '10.'mas não para '10.0'. Se você quisesse '10.'ser verdade, poderia mudar o+ depois do 0na expressão regular para *.


fonte
1

Aqui, usei algum código que parece funcionar bem e não possui nenhum dos problemas que muitos outros têm.

if (0 != strlen(str_replace(range(0, 9), '', $TestInt))) { print 'Not an integer!';}

Ele não verifica a ordem, etc., portanto não se destina a números inteiros negativos, mas com algum código de adição que pode ser feito usando algumas das outras idéias acima. Também pode ser adaptado para trabalhar com binários array('0', '1')ou hexadecimais, etc.

Dragonaire
fonte
Este é apenas um ctype_digit muito caro.
Jgmjgm
1

Veja isso. Converte $ val em número inteiro e, em seguida, verifica se o $ val original convertido em string é IDENTICAL (===) - apenas == não funcionará conforme o esperado - no valor inteiro convertido em string.

function validInt($val, $min=null, $max=null) {
    $ival = intval($val);
    //echo "'$ival' '$val'<br>\n"; // Uncomment to see the comparisons done in below if block
    if(''.$ival !== ''.$val) {
        return false;
    }
    if($min !== null && $ival < $min)
        return false;
    if($max !== null && $ival > $max)
        return false;
    return true;
}

Se você não verificar os valores das strings, pode não funcionar como o esperado:

$nums = array(
    '1',
    '+1',
    '-1',
    '01',
    '1.0',
    '.0',
    '1.123',
    'a123',
    '0x101010',
    1,
    -1,
    01,
    1.0,
    .0,
    1.123,
    0x101010,
);
foreach($nums as $num) {
    if(validInt2($num))
        echo $num." - Valid integer.<br>\n";
    else
        echo $num." - Not a valid integer.<br>\n";
}

Resultado:

1 - Valid integer.
+1 - Not a valid integer.
-1 - Valid integer.
01 - Not a valid integer.
1.0 - Not a valid integer.
.0 - Not a valid integer.
1.123 - Not a valid integer.
a123 - Not a valid integer.
0x101010 - Not a valid integer.
1 - Valid integer.
-1 - Valid integer.
1 - Valid integer.
1 - Valid integer.
0 - Valid integer.
1.123 - Not a valid integer.
1052688 - Valid integer.

Razão mesmo que você use hex (0x101010), octal (01) ou um número inteiro armazenado como float (1.0, 0.0), internamente todos serão armazenados como float. No entanto, se você usar a função para procurar int armazenado como uma sequência, ela funcionará.

Joe
fonte
1
public static function isNumeric($value, $negativ = false) {
    return is_int($value) || is_string($value) && (
        ctype_digit($value) || (
            $negativ && $value{0} == '-' && ctype_digit(substr($value, 1))
        )
    );

    //alternativ:
    //return $value == (int) $value;
}
Volker
fonte
Está faltando uma verificação nessa string! == ''. Se você colocar um número inteiro realmente longo nisso, ele também retornará true, pois algo que o PHP lançaria em um float!
Jgmjgm
1

Você pode usar a seguinte condição. Observe que você não deve usar! ==

$value = 12; // true
$value = '12'; // true
$value = 'abc'; // false
$value = 12.1; // false
$value = '12.1'; // false

if (!is_numeric($value) || (int) $value != (float) $value) {
    echo "false";
} else {
    echo "true";
}
Saman Shafigh
fonte
1

Funciona perfeitamente! Espero que seja útil para você =)

$value = 1; // true
$value = '1'; // true
$value = '1.0'; // true
$value = ' 1'; // true
$value = '01'; // true

$value = -1; // true
$value = '-1'; // true
$value = '-1.0'; // true
$value = ' -1'; // true
$value = '-01'; // true

$value = PHP_INT_MIN; // true
$value = PHP_INT_MAX; // true
$value = 0x000001; // true

$value = 'a'; // false
$value = '1a'; // false
$value = 'a1'; // false
$value = 1.1; // false
$value = '1.1'; // false
$value = '--1'; // false
$value = []; // false
$value = [1,2]; // false
$value = true; // false
$value = false; // false
$value = null; // false
$value = 'NaN'; // false
$value = 'undefined'; // false

function isInt($value) {
    return is_numeric($value) && floatval(intval($value)) === floatval($value);
}
vietbq
fonte
1
Ao responder uma pergunta antiga, sua resposta seria muito mais útil para outros usuários do StackOverflow se você incluísse algum contexto para explicar como sua resposta ajuda, principalmente para uma pergunta que já tenha uma resposta aceita. Veja: Como escrevo uma boa resposta .
David Buck
0

Se você quiser realmente saber se uma string é uma representação válida de um verdadeiro tipo inteiro PHP ...

in_array($string, array_map('strval', range(PHP_INT_MIN, PHP_INT_MAX)), true)

No entanto, isso é impossível de ser executado, pois o conjunto é muito grande (nesse caso, não caberá na memória, se você fizer um loop, em seguida, serão necessários muitos ciclos de CPU).

Talvez você possa fazer uma pesquisa binária com comparação de cadeias, no entanto, existem maneiras melhores.

O ser mais simples:

strlen($string) <= max(strlen((string)PHP_INT_MIN), strlen((string)PHP_INT_MAX)) && $string === (string)(int)$string

Existem outras maneiras incomuns de abordá-lo, como:

is_int(array_keys([$string => null])[0])

Você também pode fazer comparação de strings, mas ainda precisará fazer coisas como ctype_digit, verificar se o tamanho é razoável (não desperdice CPU antes de fazer coisas como ctype_digit) e ter um tratamento estranho para números negativos.

Observe que filter_var não afirma corretamente que uma string é realmente a representação de um número inteiro PHP. Permitirá um + e um espaço em branco circundante.

Internamente, o PHP usa a função "_zend_handle_numeric_str" para comparação estrita, mas não a expõe diretamente em nenhum lugar, daí o truque usando as chaves da matriz (que a utiliza para converter qualquer sequência que seja uma representação de um número inteiro do PHP em um número inteiro do PHP).

Se você deseja uma conversão binária segura de e para PHP, esta é a abordagem a ser adotada.

Nem todo mundo pode querer isso e pode ser um caso de manipulação de entrada do usuário. filter_var não é tão ruim assim e será bastante seguro na maioria dos casos para pessoas novas no PHP.

Uma verificação de comprimento, ctype_digit e, em seguida, uma verificação do valor convertido em um intervalo também é bastante sólido para a entrada do usuário. Esquemas mais complexos podem querer aparar ou regex.

O problema com muitas das respostas aqui a esse respeito é que, embora a pergunta seja vaga, as respostas não devem ser. Se você vai propor uma solução, deve ser capaz de explicar exatamente o que ela vai esperar e o que não vai esperar. Sem isso, não há como saber se uma resposta corresponde a uma pergunta ou é segura. O manual do PHP nem sempre ajuda porque não explica todas as advertências de cada um dos métodos relevantes que ele fornece. Coisas como ctype_digit e is_int são muito confiáveis ​​e fáceis de editar, mas as especificidades de is_numeric, filter_var e malabarismo (+ $ var) ou conversão (intval / floatval) são pouco documentadas.

Este é o fudge do PHP para você. Possui um número incontável de esquemas para interpretar cadeias de caracteres como números inteiros, com inconsistências. O método mais estrito de validar uma sequência inteira não é exposto diretamente ao usuário.

jgmjgm
fonte
0

Se você está manipulando IDs numéricos do mysql e está tentando impor uma validação para que seja um int zero diferente de zero ou um intformato mas em formato de string ( como o mysql sempre retorna tudo em formato de string ) e não NULL. Você pode usar o seguinte. Esta é a maneira mais prova de erro / aviso / aviso para permitir apenas o int/string-intsque encontrei.

...
if(empty($id) || !is_scalar($id) || !ctype_digit($id)){
  throw("Invalid ID");
}
...
Mohd Abdul Mujib
fonte
0

Aqui está uma solução simples que usa is_numeric , floatval e intval :

function is_string_an_int($string)
{
    if (is_string($string) === false)
    {
        //throw some kind of error, if needed
    }

    if (is_numeric($string) === false || floatval(intval($string)) !== floatval($string))
    {
        return false;
    }

    else
    {
        return true;
    }
}

Resultados:

is_string_an_int('-1'); //true
is_string_an_int('-1.0'); //true
is_string_an_int('-1.1'); //false
is_string_an_int('0'); //true
is_string_an_int('0.0'); //true
is_string_an_int('0.1'); //false
is_string_an_int('1'); //true
is_string_an_int('1.0'); //true
is_string_an_int('1.1'); //false
is_string_an_int('' . PHP_INT_MAX); //true
is_string_an_int('foobar'); //false
is_string_an_int('NaN'); //false
is_string_an_int('null'); //false
is_string_an_int('undefined'); //false

Observe que valores maiores que PHP_INT_MAX podem retornar false.

Pikamander2
fonte
-1

Poderia usar is_numeric () e verificar a presença de "." na string (não particularmente sensível à cultura).

Como alternativa, use is_numeric () e depois converta para um dobro e veja se $ var == floor ($ var) (deve retornar true se for um número inteiro).

Paolo
fonte
Esta é a única resposta que reconhece alterações de localidade e também altera a maneira como o PHP interpreta e gera números. Tenha muito cuidado com o setlocale e as soluções que fazem suposições sobre os separadores.
Jgmjgm 11/11