使用
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE);
是否可以反向搜索字符串?即。返回主题中最后一次出现的模式的位置,类似于strripos
或者我必须使用preg_match_all
返回所有匹配的位置并使用$matches
的最后一个元素吗?
答案 0 :(得分:24)
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]);
方式2 :使用反转模式查找反向字符串的第一个匹配项,并显示相反的结果。
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]);
方式3(变体):非常相似,但这一次,它检查不再有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]);
当您事先知道匹配的概率最大时,可以选择这两种变体中的一种(方式3或方式3(变体)之一)。
方式4 :转到字符串的末尾并回溯,直到找到x[A-Z]+\d
匹配为止。 \K
从匹配结果中删除字符串的开头。
if ( preg_match('/^.*\Kx[A-Z]+\d/', $str, $match) )
print_r($match[0]);
方式4(更多手动驱动的变体):限制回溯步骤,你可以从字符串的开头贪婪地前进,原子组中的原子组,以及原子组的方式相同,而不是字符。
if ( preg_match('/^[^x]*+(?>x[^x]*)*\Kx[A-Z]+\d/', $str, $match) )
print_r($match[0]);
答案 1 :(得分:1)
我并不完全理解你想要什么,因为它取决于将捕获多少组,我根据组号创建了捕获最后一次捕获的偏移的函数,在我的模式中,有3组:第一组,完全捕获和另外两组,分组。
模式示例代码:
$pattern = "/<a[^\x3e]{0,}href=\x22([^\x22]*)\x22>([^\x3c]*)<\/a>/";
HTML示例代码:
$subject = '<ul>
<li>Search Engines</li>
<li><a href="https://www.google.com/">Google</a></li>
<li><a href="http://www.bing.com/">Bing</a></li>
<li><a href="https://duckduckgo.com/">DuckDuckGo</a></li>
</ul>';
我的函数,它捕获最后一个元素的偏移量,你可以指出匹配的数量:
function get_offset_last_match( $pattern, $subject, $number ) {
if ( preg_match_all( $pattern, $subject, $matches, PREG_OFFSET_CAPTURE ) == false ) {
return false;
}
return $matches[$number][count( $matches[0] ) - 1][1];
}
您可以在官方文档中获取有关preg_match_all here的详细信息。
以我的模式为例:
0 =&gt;所有文字
1 =&gt; href值
2 =&gt; innerHTML
echo '<pre>';
echo get_offset_last_match( $pattern, $subject, 0 ) . PHP_EOL; // all text
echo get_offset_last_match( $pattern, $subject, 1 ) . PHP_EOL; // href value
echo get_offset_last_match( $pattern, $subject, 2 ) . PHP_EOL; // innerHTML
echo '</pre>';
die();
输出是:
140
149
174
我的功能(文字):
function get_text_last_match( $pattern, $subject, $number ) {
if ( preg_match_all( $pattern, $subject, $matches, PREG_OFFSET_CAPTURE ) == false ) {
return false;
}
return $matches[$number][count( $matches[0] ) - 1][0];
}
示例代码:
echo '<textarea style="font-family: Consolas: font-size: 14px; height: 200px; tab-size: 4; width: 90%;">';
echo 'ALL = ' . get_text_last_match( $pattern, $subject, 0 ) . PHP_EOL; // all text
echo 'HREF = ' . get_text_last_match( $pattern, $subject, 1 ) . PHP_EOL; // href value
echo 'INNER = ' . get_text_last_match( $pattern, $subject, 2 ) . PHP_EOL; // innerHTML
echo '</textarea>';
输出是:
ALL = <a href="https://duckduckgo.com/">DuckDuckGo</a>
HREF = https://duckduckgo.com/
INNER = DuckDuckGo
答案 2 :(得分:1)
“贪婪”是这里的关键词。 *默认为贪婪*?将贪婪限制在最低限度。
因此解决方案是使用组合,例如(搜索最后一个期间,后跟空白):
/^.*\.\s(.*?)$/s
答案 3 :(得分:0)
preg_match
不支持反向搜索,因为它不是必需的。
您可以创建一个RegExp,其中包含与任何内容匹配的贪婪(默认)前瞻(如(?<=.*)stuff
)。这样你就可以获得最后一次比赛了。
此处官方文档中的详细信息:preg_match