несоответствие в преобразовании строки в целое число, когда строка шестнадцатеричная с префиксом «0x» - PullRequest
3 голосов
/ 22 июня 2011

Использование PHP 5.3.5.Не уверен, как это работает в других версиях.

Я запутался в использовании строк, содержащих числа, например, '0x4B0' или '1.2e3'.То, как PHP работает с такими строками, кажется мне противоречивым.Это только я?Или это ошибка?Или недокументированная функция ?Или я просто пропускаю какое-то волшебное предложение в документах?

<?php

echo $str = '0x4B0', PHP_EOL;
echo "is_numeric() -> ", var_dump(is_numeric($str)); // bool(true)
echo "*1           -> ", var_dump($str * 1);         // int(1200)
echo "(int)        -> ", var_dump((int)$str);        // int(0)
echo "(float)      -> ", var_dump((float)$str);      // float(0)
echo PHP_EOL;

echo $str = '1.2e3', PHP_EOL;
echo "is_numeric() -> ", var_dump(is_numeric($str)); // bool(true)
echo "*1           -> ", var_dump($str * 1);         // float(1200)
echo "(int)        -> ", var_dump((int)$str);        // int(1)
echo "(float)      -> ", var_dump((float)$str);      // float(1200)
echo PHP_EOL;

В обоих случаях is_numeric() возвращает true.Кроме того, в обоих случаях $str * 1 анализирует строку и возвращает действительное число (целое число в одном случае, число с плавающей запятой в другом случае).

Приведение с (int)$str и (float)$str дает неожиданные результаты.

  • (int)$str в любом случае может анализировать только цифры, с опциональными "+" или "-" перед ними.
  • (float)$str более продвинутый и может анализировать что-то вроде ^[+-]?\d*(\.\d*)?(e[+-]?\d*)?, т. Е. Необязательные «+» или «-», за которыми следуют необязательные цифры, за которыми следует необязательная десятичная точка с необязательными цифрами, за которой следует необязательный показатель степени, состоящий из «e» с необязательными «+» или «-», за которым следует необязательныйцифры.Сбой в шестнадцатеричных данных.

Документы по теме:

  • is_numeric () - утверждает, что " Шестнадцатеричная запись (0xFF) разрешенатоже, но только без знака, десятичной и экспоненциальной части".Если функция, предназначенная для проверки, содержит ли строка числовые данные, возвращает true, я ожидаю, что PHP сможет преобразовать такую ​​строку в число.Кажется, это работает с $str * 1, но не с кастингом.Почему?
  • Преобразование в целое число - указывает, что " в большинстве случаев приведение не требуется, поскольку значение будет автоматически преобразовано, если для оператора, функции или структуры управления требуетсяцелочисленный аргумент".После такого утверждения я ожидаю, что оба выражения $s * 10 и (int)$s * 10 будут работать одинаково и возвращать одинаковый результат.Хотя, как показано в примере, эти выражения оцениваются по-разному.
  • Преобразование строки в числа - указывает, что « Допустимые числовые данные являются необязательным знаком, за которым следуют одна или несколько цифр(необязательно содержащий десятичную точку), за которым следует необязательный показатель степени".«Экспонент» - это «е» или «Е», за которыми следуют цифры, например, 1.2e3 - это действительные числовые данные.Знак («+» или «-») не упоминается.Здесь не упоминаются шестнадцатеричные значения.Это противоречит определению «числовые данные», используемому в is_numeric().Затем появляется предложение « Для получения дополнительной информации об этом преобразовании см. Справочную страницу Unix для strtod (3) », а man strtod описывает дополнительные числовые значения (включая HEX-нотацию).Итак, после прочтения этого, шестнадцатеричные данные должны быть действительными или недействительными числовыми данными?

Итак ...

  • Есть (или, скорее, должны быть) любое отношение между is_numeric() и тем, как PHP обрабатывает строки, когда они используются как числа?
  • Почему (int)$s, (float)$s и $s * 1 работают по-разному, т. е.дают совершенно разные результаты, когда $s равен 0x4B0 или 1.2e3?
  • Есть ли способ преобразовать строку в число и сохранить ее значение, если оно записано как 0x4B0 или как1.2e3?floatval() вообще не работает с HEX, для intval() необходимо установить $base на 16, чтобы работать с HEX, типизация с (int)$str и (float)$str иногда работает, иногда не работает, так что этоне действительные параметры.Я также не рассматриваю $n *= 1;, так как это больше похоже на манипулирование данными, чем на конвертацию.Самописные функции в этом случае также не рассматриваются, так как я ищу нативное решение .

Ответы [ 3 ]

3 голосов
/ 22 июня 2011

Прямое приведение (int)$str и (float)$str на самом деле совсем не работает по-разному: они оба читают столько символов из строки, сколько могут интерпретировать как число соответствующего типа.

Для«0x4B0», int-преобразование читает «0» (ОК), затем «x» и останавливается, потому что не может преобразовать «x» в целое число.Аналогично для преобразования с плавающей запятой.

Для «1.2e3» int-преобразование читает «1» (ОК), затем «.»и останавливается.Преобразование с плавающей точкой распознает всю строку как правильную запись с плавающей точкой.

Автоматическое распознавание типа для выражения типа $str * 1 просто более гибкое, чем явное приведение.Для явного приведения требуется, чтобы целые числа и числа с плавающей точкой были в формате, создаваемом %i и %f в printf, по существу.

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

Наконец, ваш вопрос "шестнадцатеричные данные должны быть действительными или недействительными числовыми данными?"неловкоНет такой вещи как "шестнадцатеричные данные".Шестнадцатеричный - это просто числовая база. Что вы можете сделать, это взять строку типа "4B0" и использовать strtoul и т. Д., Чтобы проанализировать ее как целое число в любой базе чисел от 2 до 36. [Извините, это был Б.С.Там нет strtoul в PHP.Но intval имеет эквивалентную функциональность, см. Выше.]

2 голосов
/ 22 июня 2011

intval использует strtol , который распознает префиксы oct / hex, когда параметр base равен нулю, поэтому

var_dump(intval('0xef'));     // int(0)
var_dump(intval('0xff', 0));  // int(255)
1 голос
/ 22 июня 2011

Есть (или, скорее, должно быть) какое-либо отношение между is_numeric () и тем, как PHP обрабатывает строки, когда они используются как числа?

Тип данных отсутствуетназываемая numeric в PHP, функция is_numeric() является скорее тестом для чего-то, что может быть интерпретировано PHP как число.

Что касается интерпретации такого числа, добавление + перед значением фактически заставит PHP преобразовать его в число:

$int = +'0x4B0';
$float = +'1.2e3';

Вы найдете это объясненное в руководстве для строки, ищите раздел Преобразование строки вчисла .

Поскольку он вызывается оператором, я не вижу необходимости, почему в PHP должна быть функция, которая делает то же самое.Это было бы излишним.


Внутренне PHP использует функцию под названием zendi_convert_scalar_to_number для оператора добавления (предположительно +), которая будет использовать is_numeric_string для получения числа.

Точно такая же функция вызывается изнутри is_numeric() при использовании со строками.

Поэтому, чтобы вызвать встроенную функцию преобразования, я бы просто использовал оператор +.Это обеспечит возврат числового псевдотипа (int или float).

Ref: / Zend / zend_operators.c ; / внутр / стандарт / type.c

...