With
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE);
是否可以反向搜索字符串? 即返回主题中模式最后一次出现的位置,类似于strripos
。
还是我必须返回所有匹配项的位置 preg_match_all
并使用 $matches
的最后一个元素?
PHP 没有从右到左搜索字符串的正则表达式方法(如在 .NET 中(。有几种可能的解决方法可以解决这个问题(此列表并不详尽,但它可能会为您自己的解决方法提供想法(:
- 使用带有
PREG_SET_ORDER
标志和end($matches)
的preg_match_all
将为您提供最后一个匹配集 - 用
strrev
反转字符串,并构建一个与preg_match一起使用的"反转"模式 - 使用
preg_match
并构建一个锚定在字符串末尾的模式,以确保在字符串末尾之前不再出现搜索的掩码 - 在目标和
'K
之前使用贪婪量词,在您想要的位置开始匹配结果。到达字符串末尾后,正则表达式引擎将回溯,直到找到匹配项。
模式/x[A-Z]+'d/
的字符串$str = 'xxABC1xxxABC2xx'
的示例
方式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]);
演示
变体:
使用惰性量词
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]);
贪婪"是这里的关键词。 *
默认是贪婪的,*?
贪婪将贪婪限制在最低限度。
所以解决方案是使用组合,例如(搜索最后一个句点后跟空格(,
/^.*'.'s(.*?)$/s
-
^
是文本的开头 -
.*
尽可能多地吃东西,包括匹配的模式 -
''.'s
句号后跟一个空格(我正在寻找什么( -
(.*?)
尽可能少吃。捕获组 ((,以便我可以将其作为匹配组进行寻址。 -
$
文本末尾 - 不被视为
$
和^
-.
(点(匹配换行符(
s
- 确保忽略换行符(我不明白你想要什么,因为这取决于将捕获多少组。
我做了一个函数,根据组号捕获上次捕获的偏移量。在我的模式中,我有三个组:第一组,完全捕获,另外两组,子组。
模式示例代码:
$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的详细信息。
以我的模式为例:
0 => 所有文本1 => href 值2 => 内部HTML
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
preg_match(( 不支持反向搜索,因为它不是必需的。
您可以创建一个正则表达式,其中包含与任何内容(如 (?<=.*)stuff
(匹配的贪婪(默认(前瞻。这样,您应该获得匹配的最后一次出现。
官方文档中的详细信息preg_match。