Intereting Posts
PHP mb_ereg_replace не заменяет, пока preg_replace работает по назначению обновить веб-страницу при обновлении базы данных Symfony 2: получить контекст безопасности вне контроллера Какова ценность использования PUT / DELETE с Laravel? preg_match с использованием переменной? Как я могу реализовать единый вход (SSO) с использованием Microsoft AD для внутреннего PHP-приложения? WooCommerce – Как удалить продукт и категорию продукта из URL-адресов? Как отправить электронную почту с локального сервера WAMP для отправки электронной почты Gmail Hotmail или так далее? Как сделать быстрое суждение и назначение без isset ()? PHP эквивалентен авторизированному ASP.NET WebMethod (AJAX)? использование массива в качестве источника данных для CGridView Echo 'string', в то время как каждая итерация длинного цикла (flush () не работает) Symfony – Override ProfileForm – опция 'class' не существует Перестроить модель без данных потерь в MySQL для Symfony Простой маршрут с картой Zend 1.12

несогласованность в преобразовании строки в целое число, когда строка hex, префикс '0x'

Использование 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 анализирует строку и возвращает допустимое число (целое число в одном случае, float в другом случае).

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

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

Связанные документы:

  • is_numeric () – указывает, что « шестнадцатеричная нотация (0xFF) разрешена, но только без знака, десятичной и экспоненциальной части ». Если функция, предназначенная для проверки, содержит ли строка числовые данные, возвращает true, я ожидаю, что PHP сможет преобразовать такую ​​строку в число. Кажется, что это работает с $str * 1 , но не с кастингом. Зачем?
  • Преобразование в integer – указывает, что « в большинстве случаев приведение не требуется, поскольку значение будет автоматически преобразовано, если оператор, функция или структура управления требует целочисленного аргумента ». После такого утверждения я ожидаю, что выражения $s * 10 и (int)$s * 10 будут работать одинаково и возвращать тот же результат. Хотя, как показано в примере, эти выражения оцениваются по-разному.
  • Преобразование строк в числа – указывает, что « Действительные числовые данные являются необязательным знаком, за которым следуют одна или несколько цифр (необязательно содержащие десятичную точку), а затем необязательный показатель ». «Exponent» – «e» или «E», за которым следуют цифры, например, 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, typecasting с (int)$str и (float)$str иногда работает, иногда не работает, поэтому эти являются недопустимыми. Я также не рассматриваю $n *= 1; , поскольку он больше похож на манипулирование данными, а не на преобразование. Самонаписанные функции также не рассматриваются в этом случае, поскольку я ищу собственное решение .

Solutions Collecting From Web of "несогласованность в преобразовании строки в целое число, когда строка hex, префикс '0x'"

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

Для «0x4B0» int-conversion считывает «0» (OK), затем «x» и останавливается, потому что он не может преобразовать «x» в целое число. Точно так же для float-преобразования.

Для «1.2e3» int-conversion читает «1» (OK), затем «.». и останавливается. Float-conversion распознает всю строку как допустимую нотацию с плавающей запятой.

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

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

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

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

 var_dump(intval('0xef')); // int(0) var_dump(intval('0xff', 0)); // int(255) 

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

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

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

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

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

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


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

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

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

Ссылка: /Zend/zend_operators.c ; /ext/standard/type.c