Как проверить, что строка является целым числом, а не двойным и т. Д.?

155

В PHP есть intval()функция, которая преобразует строку в целое число. Однако я хочу заранее проверить, что строка является целым числом, чтобы я мог дать пользователю полезное сообщение об ошибке, если оно неверно. PHP имеет is_int(), но это возвращает ложь для строки, как "2".

PHP имеет is_numeric()функцию, но она вернет true, если число является двойным. Я хочу что-то, что будет возвращать false для двойного, но true для int.

например:

my_is_int("2") == TRUE
my_is_int("2.1") == FALSE
Рори
источник
6
как следует относиться к "2.0"?
Ник

Ответы:

183

Как насчет использования ctype_digit?

Из руководства:

<?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";
    }
}
?>

Приведенный выше пример выведет:

Строка 1820.20 не состоит из всех цифр.
Строка 10002 состоит из всех цифр.
Строка wsl! 12 не состоит из всех цифр.

Это будет работать только если ваш ввод всегда является строкой:

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

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

Если ваш ввод может быть типа int, то объедините ctype_digitс is_int.

Если вы заботитесь о отрицательных числах, то вам необходимо проверить вход для предшествующего -, и если да, то вызов ctype_digitна substrвходной строку. Что-то вроде этого сделало бы это:

function my_is_int($input) {
  if ($input[0] == '-') {
    return ctype_digit(substr($input, 1));
  }
  return ctype_digit($input);
}
Доминик Роджер
источник
7
отрицательные числа?
Анураг
1
@Anurag, отредактировано в (хотя, если вы действительно заботитесь об этом материале, регулярное выражение, вероятно, проще).
Доминик Роджер
4
Если вы хотите проверить наличие отрицательных целых чисел, добавьте использование abs (), например, ctype_digit(abs($str))вместо just ctype_digit.
Enchance
3
@enchance abs('definitelynotanint') === 0. кроме того, ctype_digitпринимает только строки
Klesun
Это не правильно. Большое целое число в PHP - это двойное число!
jgmjgm
91

filter_var следует сделать это:

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

но

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

Если вы просто хотите, чтобы логические значения были возвращаемыми значениями, оберните их в функцию, например

function validatesAsInt($number)
{
    $number = filter_var($number, FILTER_VALIDATE_INT);
    return ($number !== FALSE);
}
Гордон
источник
2
Мне нравятся большинство ответов, но я думаю, что этот самый элегантный.
Ян Данн
6
@grenoult 3v4l.org/qVRRS дает int 0 для строк и целых чисел, поэтому не уверен, почему вы думаете, что он не работает. Вы сравниваете результат с ==возможно?
Гордон
1
@Gordon моя ошибка, я действительно сравнивал только с if 3v4l.org/IAvCF
Гийом
Это приведет к некоторым странным вещам, таким как возврат true для "+123". Это смягчается тем, что оно предназначено для возврата истинного значения int, но все равно может не соответствовать желаемому, что является строгой проверкой int.
jgmjgm
@ MohammedRédaOUASSINI ОП попросил проверять строки , а не значения с плавающей точкой. Он будет работать, если вы передадите -1.0 (строка). Он не будет работать, если вы передадите -1.0 (число с плавающей запятой), но это не было обязательным условием для начала. См. 3v4l.org/bOX6X
Гордон
20

+1 к ответу Доминика (используя ctype_digit). Другой способ, которым вы могли бы сделать это, с помощью приведения типа:

$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
источник
2
+1 вам тоже (хотя мне интересно, если бы этот конкретный случай был обработан более четко, обрезая входную строку).
Доминик Роджер
6
Этот метод не работает для нечисловых строк: is_int ("abc" +0) имеет значение true
Кай Поммеренке
1
Правда, это не работает для нечисловых строк ... что насчет is_int($inty + 0) && is_numeric($inty)(я знаю, что это ленивое решение, но работает для большинства намерений и целей ...
Алекс Мантаут
Использование жонглирования типов приведет к довольно слабой проверке, где целые числа могут быть представлены всевозможными строковыми способами, это не проверка строк. Тебе тоже не нужно +0. Вы можете просто + $ var.
jgmjgm
13

Приведите его к int. если он все еще имеет то же значение, то его int;

function my_is_int($var) {
  $tmp = (int) $var;
  if($tmp == $var)
       return true;
  else
       return false;
}
Greg
источник
2
Или еще короче:return $var == (int) $var;
Ал.Г.
1
@ AI.G. Что случится, если произойдет сбой
DR.
Это очень близко, следует избегать жонглирования типов, хотя если это не нужно. Это будет работать, если $ var равно «123xxxx».
jgmjgm
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);
    }
}

Источник .

GmonC
источник
вместо того, чтобы разбрасывать мой код небольшими служебными функциями, я бы предпочел что-то встроенное в php.
Рори
Мне тоже не нравятся эти хаки. Но, используя этот подход или предложение ctype от Dominic, вы все равно инкапсулируете всю реализацию в методе. При использовании php у меня всегда есть класс "Util" для решения этих проблем.
GmonC
elseifможет быть просто ifпотому, что вы уже вернулись в заявлении над ним.
rybo111
Также нет необходимости возвращать false в конце.
rybo111
1
Если $dataэто объект, он вернется null. Лучше иметь return false;в конце.
Теодор Р. Смит
6

Нужна была крепкая в is_intпоследнее время. Я нашел intval () слишком непредсказуемым:

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


Этот фрагмент встречался в комментариях к документации PHP, и после тестирования он охватывает практически все, что вы на него бросаете:

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


Но осторожно:

my_is_int(2.0); //true
my_is_int("2.0"); //true
ребро
источник
6

Один действительно чистый способ, который мне нравится использовать, - это тот. Вы разыгрываете его дважды, сначала в int, во вторую string, затем вы строго сравниваете ===. Смотрите пример ниже:

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

Теперь о вашей функции my_is_int вы можете сделать что-то вроде этого:

function my_is_int($value){ return $value === (string)(int)$value; }
my_is_int('2');  // true
my_is_int('2.1') // false
Джонатан Ганье
источник
4
function my_is_int($var) {
    return preg_match('/^\d+$/', $var);
}
Майкл Коннор
источник
1
Я использовал эту вариацию, позволяя использовать числовой сигнал:'/^[-+]?[0-9]+$/'
Денилсон Са Майя,
Это то же самое, что и ctype_digit, оно также допускает завершающий перевод новой строки.
jgmjgm
3

Я использую это:

function isInt($val){

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

}

var_dump (isInt("1"));
julesdude
источник
3

Вы можете просто проверить число, если оно проверено, то если приведение удвоено или нет:

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

Просто для положительных чисел:

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

Проверяем это:

$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));
}

Вывод:

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)
Хорди Мартинес
источник
is_numeric () было то, что я искал.
ccjjmartin
1
Чтобы убедиться, что это именно то, что вам нужно, вам нужно прочитать исходный код PHP, так как он недостаточно хорошо документирован. Например, is_numeric принимает начальные пробелы, что не описано в руководстве по PHP. Следует также иметь в виду, что строковые целые числа, которые слишком велики, чтобы быть представленными с собственным int, конвертируются в float.
jgmjgm
2

Попробуй это:

$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!

Также работает, если ваша строка $ имеет десятичные разряды

Джек М.
источник
Это будет рассматривать 123xxxx как допустимую строку int.
jgmjgm
2

Это позаботится и об отрицательном числе

function myIsInt()
{
   return (is_numeric($var) AND (is_int($var) OR ctype_digit(trim($var, '-'))))
}
//'234-' => false
//'-234' => true
//'--234' => false
//'234' => true
wolakpaul
источник
Я не понимаю, почему это вернуло бы false для 234 или - 234, вы проверяли это? Это вернет истину для ----- 1234 ----
jgmjgm
2
function my_is_int($var){
    return is_numeric($var) && gettype($var+0)=='integer';
}
даровать солнце
источник
2

Я придумал способ, который нигде не мог найти, поэтому я помещаю это здесь:

Без дальнейших церемоний это так: ctype_digit((string) abs($input))

Пример:

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;
}

Результаты: (как и ожидалось, я полагаю)

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
источник
abs преобразует ввод из строки в число. Это то же самое, что is_int (+ $ var).
jgmjgm
2

Возможно, не самый эффективный способ сделать это. Но вы можете написать это в одну строку.

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

Как и ожидалось:

    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

Попался:

    my_is_int(1.0);   // TRUE
    my_is_int("1.0"); // FALSE
mwallisch
источник
Это правильно, если вы уверены, что $ input имеет тип string.
jgmjgm
2

Несколько лет спустя, но, основываясь на ответах, приведенных здесь, я нашел решение, которое было бы несколько более точным (в частности, по логическим значениям) и более эффективным (я думаю), чем большинство других ответов:

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

Работая как ожидалось для этих:

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

За исключением, может быть, для этих 2:

my_is_int(0x101010);            // true
my_is_int("-2");                // false
SharkWipf
источник
очень хорошо. если вы хотите обработать числовую строку с отрицательным знаком, вы можете изменить ее на ctype_digits (preg_replace ('/ ^ - /', '', $ s)), хотя это начинает становиться немного запутанным. Кроме того, 0x101010 является целым числом, так что это не ошибка, скорее, «0x101010» может считаться неправильным, и я уверен, что двоичные строки, соответствующие двоичной литеральной записи («0b11111»), тоже не будут работать
fbas
1

Как насчет:

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;
}

Эта функция должна возвращать true только для любого строкового числа, которое может быть приведено к int с потерей (int)или intval()без потери чего-либо математического значения (например, ненулевых значений после десятичной точки или чисел за пределами целочисленного диапазона PHP), принимая при этом вещи, которые не являются математически значимыми (например, пробел; начальные нули; или, после десятичной точки, исключительно нули).

Он вернет ложь для, '10.'но не для '10.0'. Если вы хотите '10.'быть правдой, вы можете изменить +после 0в регулярном выражении после *.


источник
1

Вот некоторый код, который я использовал, который, кажется, работает хорошо и не имеет проблем, которые делают многие другие.

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

Он не проверяет порядок и т. Д., Поэтому он предназначен не для отрицательных целых чисел, а с некоторым дополнительным кодом, который также может быть выполнен с использованием некоторых других идей, приведенных выше. Он также может быть адаптирован для работы с двоичными array('0', '1')или шестнадцатеричными числами и т. Д.

Dragonaire
источник
Это просто очень дорогой ctype_digit.
jgmjgm
1

Посмотри это. Преобразует $ val в целое число, а затем проверяет, является ли исходный $ val, преобразованный в строку, IDENTICAL (===) - просто == не будет работать должным образом - в целое число val, преобразованное в строку.

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;
}

Если вы не проверяете строковые значения, они могут работать не так, как вы ожидаете:

$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";
}

Вывод:

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.

Причина в том, что даже если вы используете шестнадцатеричный (0x101010), восьмеричный (01) или целое число, хранящееся как float (1.0, 0.0), внутренне все они хранятся как float. Однако если вы используете функцию для проверки на наличие int, хранящегося в виде строки, она будет работать.

Джо
источник
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
источник
Здесь отсутствует проверка этой строки! == ''. Если вы введете в него действительно длинное целое число, оно также вернет true для чего-то, что PHP будет приводить к float!
jgmjgm
1

Вы можете использовать следующее условие. Обратите внимание, что вы не должны использовать! ==

$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";
}
Саман Шафиг
источник
1

Работает отлично! Надеюсь, это будет полезно для вас =)

$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
источник
1
При ответе на старый вопрос ваш ответ был бы гораздо более полезным для других пользователей StackOverflow, если бы вы включили некоторый контекст для объяснения того, как ваш ответ помогает, особенно для вопроса, на который уже есть принятый ответ. Смотрите: Как мне написать хороший ответ .
Дэвид Бак
0

Если вы хотите действительно знать, является ли строка правильным представлением истинного целочисленного типа PHP ...

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

Однако это невозможно запустить, так как набор слишком велик (в этом случае он не помещается в память, если вы зациклите его, это займет слишком много циклов ЦП).

Возможно, вы можете выполнить бинарный поиск со сравнением строк, однако есть и лучшие способы.

Самое простое существо:

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

Есть несколько других необычных способов приблизиться к этому, таких как:

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

Вы также можете выполнять сравнение строк, но вам все равно нужно будет делать такие вещи, как ctype_digit, проверять разумность длины (не тратьте ЦП, прежде чем делать такие вещи, как ctype_digit) и иметь некоторую неловкую обработку для отрицательных чисел.

Обратите внимание , что filter_var не правильно утверждать , что строка действительно представление РНР целое. Это позволит ведущий + и окружающие пробелы.

Внутренне PHP использует функцию "_zend_handle_numeric_str" для строгого сравнения, но он нигде не раскрывает это напрямую, отсюда и хитрость с использованием ключей массива (которая использует ее для преобразования любой строки, представляющей целое число PHP, в целое число PHP).

Если вы хотите, чтобы двоичное безопасное преобразование в и из PHP это подход.

Не каждый может захотеть этого, и это может быть случай обработки пользовательского ввода. filter_var не так уж плох для этого и в большинстве случаев будет достаточно безопасным для новичков в PHP.

Проверка длины, ctype_digit и затем проверка преобразованного значения, что оно находится в диапазоне, также достаточно надежны для ввода пользователем. Более сложные схемы могут потребовать обрезки или регулярного выражения.

Проблема с большим количеством ответов здесь в этом отношении состоит в том, что, хотя вопрос является расплывчатым, ответы не должны быть. Если вы собираетесь предложить решение, вы должны быть в состоянии объяснить, что именно оно будет и не ожидать. Без этого нельзя сказать, соответствует ли ответ на вопрос или является безопасным. Руководство по PHP не всегда помогает, потому что оно не объясняет все предостережения для каждого из соответствующих методов, которые оно предоставляет. Такие вещи, как ctype_digit и is_int очень надежны и их легко предопределить, но особенности is_numeric, filter_var и juggling (+ $ var) или приведение типов (intval / floatval) плохо документированы.

Это PHP выдумка для вас. У него есть бесчисленное множество схем для интерпретации строк как целых чисел с несоответствиями. Самый строгий метод проверки целочисленной строки не предоставляется непосредственно пользователю.

jgmjgm
источник
0

Если вы обрабатываете числовые идентификаторы из mysql и пытаетесь навязать валидацию для него, чтобы оно было действительным ненулевым int или intно в строковом формате (так как mysql всегда возвращает все в строковом формате ), а не так NULL. Вы можете использовать следующее. Это наиболее надежный способ подтверждения ошибок / предупреждений / уведомлений, int/string-intsкоторый я обнаружил.

...
if(empty($id) || !is_scalar($id) || !ctype_digit($id)){
  throw("Invalid ID");
}
...
Мохд Абдул Муджиб
источник
0

Вот простое решение, которое использует is_numeric , floatval и 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;
    }
}

Полученные результаты:

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

Обратите внимание, что значения, превышающие PHP_INT_MAX, могут возвращать false.

Pikamander2
источник
-1

Можно использовать is_numeric (), а затем проверить наличие "." в строке (не особо чувствительный к культуре, хотя).

В качестве альтернативы используйте is_numeric (), затем приведите к двойному и посмотрите, будет ли $ var == floor ($ var) (должно возвращать true, если это целое число).

Paolo
источник
Это единственный ответ, который распознает изменения локали, а также меняет то, как PHP интерпретирует и выводит числа. Будьте очень осторожны с setlocale и решениями, которые делают предположения о разделителях.
jgmjgm