PHP preg_match() 返回最后一次匹配的位置

标签 php regex preg-match

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]);

Demo

方式二:找到第一个匹配反转模式的反转字符串,并显示反转结果。

if ( preg_match('/\d[A-Z]+x/', strrev($str), $match) )
    print_r(strrev($match[0]));

Demo

请注意,反转模式并不总是那么容易。

方式 3:从 x 跳到 x,如果没有其他 x[A-Z]+\d 匹配,则使用负前瞻检查字符串。

if ( preg_match('/x[A-Z]+\d(?!.*x[A-Z]+\d)/', $str, $match) )
    print_r($match[0]);

Demo

变体:

带有惰性量词

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/

相关文章:

php - 使用ajax将数据多次插入表中

php - Mysql 正则表达式按数字选择

php - 如何通过 while 循环的两个值之和重新排序?

php - 我的正则表达式出了什么问题?

用于验证文件夹名称和文件名的正则表达式

PHP 正则表达式 : match text urls until space or end of string

php - 如何在 php 中正确打印此标记

Java - 提取后缀和前缀中间的字符串

ReplaceAll 正则表达式引起的 Java OutOfMemoryError

javascript - 使用正则表达式匹配名称字符串中的首字母忽略标题