与
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE);
是否可以反向搜索字符串?即,返回主题中模式最后一次出现的位置,类似于 strripos
。
或者我是否必须使用 preg_match_all
返回所有匹配项的位置并使用 $matches
的最后一个元素?
最佳答案
PHP 没有从右到左搜索字符串的正则表达式方法(如 .NET )。有几种可能的方法可以解决这个问题(此列表并不详尽,但它可能会为您自己的解决方法提供想法):
- 使用
preg_match_all
带有PREG_SET_ORDER
标志和end($matches)
会给你最后的匹配集 - 用
strrev
反转字符串并构建一个“反向”模式以与 preg_match 一起使用 - 使用
preg_match
并构建一个锚定在字符串末尾的模式,以确保在字符串末尾之前不会再出现搜索到的掩码 - 在目标和
\K
之前使用一个贪婪的量词来在你想要的位置开始匹配结果。到达字符串末尾后,正则表达式引擎将回溯,直到找到匹配项。
带有字符串 $str = 'xxABC1xxxABC2xx'
的示例 /x[A-Z]+\d/
方式 1:查找所有匹配项并显示最后一个。
if ( preg_match_all('/x[A-Z]+\d/', $str, $matches, PREG_SET_ORDER) )
print_r(end($matches)[0]);
方式二:找到第一个匹配反转模式的反转字符串,并显示反转结果。
if ( preg_match('/\d[A-Z]+x/', strrev($str), $match) )
print_r(strrev($match[0]));
请注意,反转模式并不总是那么容易。
方式 3:从 x 跳到 x,如果没有其他 x[A-Z]+\d
匹配,则使用负前瞻检查字符串。
if ( preg_match('/x[A-Z]+\d(?!.*x[A-Z]+\d)/', $str, $match) )
print_r($match[0]);
变体:
带有惰性量词
if ( preg_match('/x[A-Z]+\d(?!.*?x[A-Z]+\d)/', $str, $match) )
print_r($match[0]);
或使用“调节量词”
if ( preg_match('/x[A-Z]+\d(?=(?:(?!x[A-Z]+\d).)*$)/', $str, $match) )
print_r($match[0]);
当您事先知道匹配最有可能发生的位置时,在这些变体之间进行选择会很有趣。
方式 4:转到字符串末尾并回溯,直到找到 x[A-Z]+\d
匹配项。 \K
从匹配结果中删除字符串的开头。
if ( preg_match('/^.*\Kx[A-Z]+\d/', $str, $match) )
print_r($match[0]);
方式 4(更手动的变体):为了限制回溯步骤,您可以贪婪地从字符串的开头开始前进,逐个原子组,并在按照原子组而不是字符的方式相同。
if ( preg_match('/^(?>[^x]*\Kx)+[A-Z]+\d/', $str, $match) )
print_r($match[0]);
关于PHP preg_match() 返回最后一次匹配的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23343087/