从字符串中提取一个单独的(无符号)整数

396

我想从包含数字和字母的字符串中提取数字:

"In My Cart : 11 items"

我想提取数字 11

23个回答

7

由于您的字符串中只有一个数字值需要隔离,我将推荐并个人使用filter_var()FILTER_SANITIZE_NUMBER_INT

echo filter_var($string, FILTER_SANITIZE_NUMBER_INT);

一种更为奇怪但有效的技巧是使用 ltrim() 函数与字符掩码,将剩余的字符串转换成整数,因为在这种情况下只有1个数值和该整数之前的唯一字符都是字母、冒号或空格。

演示

$string = "In My Cart : 11 items";
echo (int)ltrim($string, 'A..z: ');
// 11

如果由于某种原因出现了多个整数值并且您想要获取第一个,则正则表达式将是一种直接的技术。

演示

echo preg_match('/\d+/', $string, $m) ? $m[0] : '';

sscanf()十分方便,如果您需要将数字字符串显式转换为整数(或浮点数)。 如果整数值可能/未知出现在字符串的开头,则在扫描输入字符串之前在其前面添加一个非数字字符。以下技术匹配前导非数字字符(并使用后面的*忽略它们),然后匹配第一次出现的数字序列,并将返回的子字符串转换为整数。

演示

var_dump(sscanf(' ' . $string, '%*[^0-9]%d')[0]);

要将此技术用于提取浮点值,只需更改 df。有关sscanf()(目前未记录的)赋值抑制功能的更多信息,请参见此帖子

6
您可以使用以下函数:
function extract_numbers($string)
{
   preg_match_all('/([\d]+)/', $string, $match);

   return $match[0];
}

在字符类中写入\d没有任何好处。由于您正在访问完整的字符串匹配,因此在模式中编写捕获组是没有意义的。 - mickmackusa
OP只有一个整数需要隔离--preg_match_all()不是解决所提问题的合适工具。这个答案最多只能算是对另一个问题的回答。 - mickmackusa

5
preg_match_all('!\d+!', $some_string, $matches);
$string_of_numbers = implode(' ', $matches[0]);

在这种特定情况下,implode中的第一个参数表示“使用单个空格分隔matches [0]中的每个元素”。implode不会在第一个数字之前或最后一个数字之后放置空格(或其他第一个参数)。
另外需要注意的是$matches [0]存储匹配此正则表达式的所有匹配项的数组。
有关数组中其他索引用途的进一步澄清,请参见:http://php.net/manual/en/function.preg-match-all.php

对于 OP 的示例输入,preg_match_all() 是不必要的额外工作,并且它创建了一个具有不必要深度的 $matches 数组。这看起来像是那种完全忘记了 OP 在问题中所问的内容的问题。 - mickmackusa

4

尝试使用preg_replace函数进行操作。

$string = "Hello! 123 test this? 456. done? 100%";
$int = intval(preg_replace('/[^0-9]+/', '', $string), 10);
echo $int;

DEMO


"[^0-9]" 更简单的写法是 "\D"。 - mickmackusa
为什么楼主想把所有这些值都压缩成一个值呢?123456100有什么可能的用途? - mickmackusa

3

你为什么要考虑小数位?你读了OP的问题吗?OP的用户如何在购物车中有一部分商品? - mickmackusa

3

按照以下步骤操作,即可将字符串转换为数字

$value = '$0025.123';
$onlyNumeric = filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
settype($onlyNumeric,"float");

$result=($onlyNumeric+100);
echo $result;

另外一种方法:

$res = preg_replace("/[^0-9.]/", "", "$15645623.095605659");

你有读懂问题吗?OP的用户如何在购物车中只有一部分商品?还是你只看了其他答案,忘记看OP实际上问了什么? - mickmackusa

2

使用sscanf的另一种解决方案:

$str = "In My Cart : 11 items";
list($count) = sscanf($str, 'In My Cart : %s items');

这是一个非常明智的技巧,适用于这种特定情况(其中字符串的非数字部分是可预测的静态)。研究人员可能会发现,%d也可以用于将数字子字符串转换为整数类型数据。https://3v4l.org/lLTXv @salathe在2011年提到了这个技巧,但被OP说服删除答案,理由是完整的字符串没有可靠的静态格式。(文本的可变性应该由OP澄清。) - mickmackusa

2

另一种方式(甚至是Unicode字符串):

$res = array();
$str = 'test 1234 555 2.7 string ..... 2.2 3.3';
$str = preg_replace("/[^0-9\.]/", " ", $str);
$str = trim(preg_replace('/\s+/u', ' ', $str));
$arr = explode(' ', $str);
for ($i = 0; $i < count($arr); $i++) {
    if (is_numeric($arr[$i])) {
        $res[] = $arr[$i];
    }
}
print_r($res); //Array ( [0] => 1234 [1] => 555 [2] => 2.7 [3] => 2.2 [4] => 3.3 ) 

我不明白为什么这段未解释的代码不使用preg_split(),而要用这么复杂的方法。 - undefined

-1
如果您不知道数字是什么格式?整数还是浮点数,请使用以下代码:
$string = '$125.22';

$string2 = '$125';

preg_match_all('/(\d+.?\d+)/',$string,$matches); // $matches[1] = 125.22

preg_match_all('/(\d+.?\d+)/',$string2,$matches); // $matches[1] = 125

捕获组是不必要的,因为您正在捕获完整的字符串匹配 - 实际上将匹配数组的大小加倍,而没有任何好处。如果输入字符串仅以“$”开头,则只需使用ltrim($string,'$') - mickmackusa

-2

对于UTF8字符串:

function unicodeStrDigits($str) {
    $arr = array();
    $sub = '';
    for ($i = 0; $i < strlen($str); $i++) { 
        if (is_numeric($str[$i])) {
            $sub .= $str[$i];
            continue;
        } else {
            if ($sub) {
                array_push($arr, $sub);
                $sub = '';
            }
        }
    }

    if ($sub) {
        array_push($arr, $sub); 
    }

    return $arr;
}

这绝对不是utf8准备好的,因为你没有使用mb_函数,而且你使用[offset]语法来访问字符串中的每个字节。这个未解释的答案是“不好的”。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接