我正在编写一个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'
明显的结果是数组([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 )'
我想问的是,有没有更简单、更安全或更有效的方法可以达到这个效果?
4条答案
按热度按时间42fyovps1#
如果我没理解错的话,你想拆分一个下划线分隔的字符串,并过滤掉任何非数字的子字符串,如果是这样的话,这可以不用regex,用
explode()
,array_filter()
和ctype_digit()
来实现;例如:这产生:
请注意,
ctype_digit()
:检查提供的字符串中的所有字符是否都是数字。
所以
$digits
仍然是一个字符串数组,尽管是数值。希望这有帮助:)
tpxzln5u2#
只获取分解后字符串的数字部分
结果
vaqhlq813#
使用strtok
Regex不是灵丹妙药,对于您的问题,有更简单的解决方法,特别是考虑到您正试图在分隔符上进行拆分。
下面的任何一种方法都会更干净,更易于维护,而
strtok()
方法 * 可能 * 会表现得更好:1.使用explode创建并循环遍历一个数组,检查每个值。
1.使用preg_split也可以做同样的事情,但是使用了一种适应性更强的方法。
1.使用strtok,因为它正是为此用例设计的。
explode
的方法可能会带来更好的性能。对于这样的解决方案,请参阅本主题中的其他答案:https://stackoverflow.com/a/46937452/1589379.5cg8jx4n4#
此任务只需通过一个
preg_match_all()
调用即可完成。使用匹配一个或多个数字的模式,该模式为:
1.前面带有字符串的开头或下划线,并且
1.后跟下划线或字符串结尾。
代码:(Demo)