将字符串转换为整数时的不一致,当字符串为十六进制时,前缀为“0x”

时间:2011-06-22 11:13:43

标签: php string-conversion

使用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,但不适用于强制转换。为什么?
  • Converting to integer - 声明“在大多数情况下不需要强制转换,因为如果运算符,函数或控制结构需要整数参数,则会自动转换一个值”。在这样的陈述之后,我希望$s * 10(int)$s * 10表达式以相同的方式工作并返回相同的结果。但是,如示例所示,这些表达式的评估方式不同。
  • String conversion to numbers - 声明“有效数字数据是可选符号,后跟一个或多个数字(可选地包含小数点),后跟可选指数”。 “指数”是“e”或“E”,后跟数字,例如1.2e3是有效的数字数据。未提及符号(“+”或“ - ”)。它没有提到十六进制值。这与is_numeric()中使用的“数字数据”的定义相冲突。然后,建议“有关此转换的更多信息,请参阅strtod(3)的Unix手册页”,man strtod描述其他数值(包括HEX表示法)。那么,在阅读之后,十六进制数据是否应该是有效的或无效的数字数据?

因此...

  • is_numeric()和PHP在用作数字时如何处理字符串的方式之间是否存在(或者更确切地说应该存在)?
  • 为什么(int)$s(float)$s$s * 1的工作方式不同,即。当$s0x4B01.2e3
  • 时,会给出完全不同的结果
  • 有没有办法将字符串转换为数字并保留其值,如果它被写为0x4B01.2e3floatval()根本不适用于HEX,intval()需要将$base设置为16以使用HEX,使用(int)$str和{{1}进行类型转换有时工作,有时不起作用,所以这些都不是有效的选择。我也没有考虑(float)$str,因为它看起来更像数据操作而不是转换。在这种情况下,也不考虑自编函数,因为我正在寻找原生解决方案

3 个答案:

答案 0 :(得分:3)

直接强制转换(int)$str(float)$str根本不会有不同的工作方式:它们都会从字符串中读取尽可能多的字符,因为它们可以解释为相应类型的数字。

对于“0x4B0”,int转换读取“0”(OK),然后“x”并停止,因为它不能将“x”转换为整数。同样适用于浮动转换。

对于“1.2e3”,int转换为“1”(OK),然后为“。”。并停止。 float-conversion将整个字符串识别为有效的浮点符号。

$str * 1这样的表达式的自动类型识别比显式强制转换更灵活。显式强制转换要求整数和浮点数采用%i%fprintf生成的格式。{/ p>

或许您可以使用intvalfloatval而不是显式的强制转换为int,以获得更大的灵活性。

最后,您的问题“是十六进制数据应该是有效还是无效的数字数据?”很尴尬。没有“十六进制数据”这样的东西。十六进制只是一个数字基础。 和36。 [抱歉,那是BS。 PHP中没有strtoul。但是strtoul具有相同的功能,请参见上文。]

答案 1 :(得分:2)

intval使用strtolbase参数为零时识别oct / hex前缀,所以

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

答案 2 :(得分:1)

  

是否存在(或者更确切地说,应该存在)is_numeric()与PHP在将字符串用作数字时如何处理它们之间的关系?

PHP中没有名为 numeric 的数据类型,is_numeric()函数更像是可以被PHP解释为数字的测试。

就这样的数字解释而言,在值前添加+实际上会使PHP将其转换为数字:

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

您会发现in the manual for string, look for the section String conversion to numbers解释了这一点。

由于它是由运算符触发的,我认为没有必要为什么在PHP中应该有一个函数来执行相同的操作。那将是多余的。


内部PHP使用名为zendi_convert_scalar_to_number的函数作为add运算符(可假设+),它将使用is_numeric_string来获取数字。

当与字符串一起使用时,is_numeric()会在内部调用完全相同的函数。

因此,要触发本机转换功能,我只需使用+运算符。这将确保您将返回数字伪类型(int或float)。

参考:/Zend/zend_operators.c; /ext/standard/type.c