从字符串中提取数字块时如何避免混合字母数字

问题描述 投票:0回答:4

我正在编写一个 PHP 函数来从字符串中提取数字 ID,例如:

$test = '123_123_Foo'

一开始我采取了两种不同的方法,一种是

preg_match_all()

$test2 = '123_1256_Foo';
preg_match_all('/[0-9]{1,}/', $test2, $matches);
print_r($matches[0]); // Result: 'Array ( [0] => 123 [1] => 1256 )'

以及其他与

preg_replace()
explode()
:

$test = preg_replace('/[^0-9_]/', '', $test);
$output = array_filter(explode('_', $test));
print_r($output); // Results: 'Array ( [0] => 123 [1] => 1256 )'

只要字符串不包含混合字母和数字,其中任何一个都可以正常工作,例如:

$test2 = '123_123_234_Foo2'

明显的结果是 Array ( [0] => 123 [1] => 1256 [2] => 2 )

所以我编写了另一个正则表达式来摆脱混合字符串:

$test2 = preg_replace('/([a-zA-Z]{1,}[0-9]{1,}[a-zA-Z]{1,})|([0-9]{1,}[a-zA-Z]{1,}[0-9]{1,})|([a-zA-Z]{1,}[0-9]{1,})|([0-9]{1,}[a-zA-Z]{1,})|[^0-9_]/', '', $test2);
$output = array_filter(explode('_', $test2));
print_r($output); // Results: 'Array ( [0] => 123 [1] => 1256 )'

问题也很明显,像 Foo2foo12foo1 这样更复杂的模式会通过过滤器。这就是我有点卡住的地方。

回顾:

  • 从字符串中提取可变数量的数字块。
  • 字符串至少包含1个数字,也可能包含其他数字 和字母之间用下划线分隔。
  • 只能提取前面或后面没有字母的数字。
  • 只有字符串前半部分的数字才重要。

由于只需要前半部分,我决定将第一次出现的字母或混合数字字母与

preg_split()
:

分开
$test2 = '123_123_234_1Foo2'
$output = preg_split('/([0-9]{1,}[a-zA-Z]{1,})|[^0-9_]/', $test, 2);
preg_match_all('/[0-9]{1,}/', $output[0], $matches);
print_r($matches[0]); // Results: 'Array ( [0] => 123 [1] => 123 [2] => 234 )'

我的问题的重点是是否有更简单、更安全或更有效的方法来实现这个结果。

php regex
4个回答
3
投票

这可以在没有正则表达式的情况下实现,使用

explode()
array_filter()
ctype_digit()
;例如:

<?php

$str = '123_123_234_1Foo2';

$digits = array_filter(explode('_', $str), function ($substr) {
  return ctype_digit($substr);
});

print_r($digits);

这产生:

Array
(
    [0] => 123
    [1] => 123
    [2] => 234
)

请注意

ctype_digit()

检查提供的字符串中的所有字符是否都是数字。

所以

$digits
仍然是一个字符串数组,尽管是数字。

希望这有帮助:)


3
投票

使用strtok

正则表达式不是灵丹妙药,对于您的问题有更简单的解决方案,特别是考虑到您试图在分隔符上进行拆分。

以下任何方法都会更干净,更易于维护,并且

strtok()
方法会可能表现更好:

  1. 使用 explode 创建并循环遍历数组,检查每个值。
  2. 使用 preg_split 执行相同的操作,但采用更具适应性的方法。
  3. 使用 strtok,因为它是专门针对此用例设计的。

您的案例的基本示例:

function strGetInts(string $str, str $delim) {
    $word = strtok($str, $delim);

    while (false !== $word) {
        if (is_integer($word) {
            yield (int) $word;
        }
        $word = strtok($delim);
    }   
}

$test2 = '123_1256_Foo';

foreach(strGetInts($test2, '_-') as $key {
    print_r($key);
}

注意: strtok 的第二个参数是包含用于分割字符串的任何分隔符的字符串。因此,我的示例将结果分组为由下划线或破折号分隔的字符串。

附加说明:当且仅当字符串仅需要在单个分隔符(仅下划线)上拆分时,使用

explode
的方法可能会带来更好的性能。对于这样的解决方案,请参阅此线程中的其他答案:https://stackoverflow.com/a/46937452/1589379 .


3
投票

爆炸后仅获取字符串的数字部分

$test2  = "123_123_234_1Foo2";
$digits = array_filter(
                       explode('_', $test2 ), 
                       'ctype_digit'
);
var_dump($digits);

结果

array(3) {
  [0]=>
  string(3) "123"
  [1]=>
  string(3) "123"
  [2]=>
  string(3) "234"
}

0
投票

此任务只需一次

preg_match_all()
调用即可完成。

使用与一个或多个数字匹配的模式:

  1. 前面是字符串或下划线的开头,并且是
  2. 后跟下划线或字符串结尾。

代码:(演示

$test2 = '123_123_234_1Foo2';
preg_match_all('/(?<=^|_)\d+(?=_|$)/', $test2, $m);
var_export($m[0]);
© www.soinside.com 2019 - 2024. All rights reserved.