PHP递归正则表达式的语法


Syntax for recursive regex in PHP

我错过了一些让我在使用递归(?R)时失败的东西。

一个解释我的问题的例子:

$str1 = "somes text -start bla bla FIND bla bla bla FIND bla FIND bla end-";
$str2 = "somes text -start bla bla FIND bla bla bla FIND bla FIND bla end-";
$my_pattern = "-start .*(FIND).* end-";
preg_replace_callback($my_pattern, 'callback', $str1.$str2);

它只匹配最后一个FIND。

使用'ungreedy'选项,我将匹配两个$str的第一个FIND。

但是我怎样才能得到所有的呢?我试着使用'(?R)',但我真的不明白它是如何工作的。

谢谢。

编辑:真正的工作是找到<a> &</a>。我知道这不是优化使用正则表达式解析html,但它只是一个工作从学校学习正则表达式。

这就是为什么我没有投入真正的工作,我想要理解并能够自己做。

<html>
 <head><title>Nice page</title></head>
<body>
    Hello World
 <a href=http://cyan.com title="a link">
                this is a link
 </a>
<br />
<a href=http://www.riven.com> Here too <img src=wrong.image title="and again">
    <span>Even that<div title="same">all the same</div></span>
</a>
</body>
</html>

我的工作是使用regex将每个标题都大写(例如title="A LINK")。

我的最后一个模式是:

#<a .* title='"(.*)'".*</a>#Uis

让我抓住了(title="a link")和(title="and again")。你的方法应该工作(stribizhev),但我没有成功实现它,我仍然在它。

更新答案-更改HTML中的大小写

你需要使用DOMDocument与DOMXPath安全地获得所有标题属性和改变他们与mb_strtoupper:

$html = "<<YOUR_HTML>>";
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
$titles = $xpath->query('//a[@title]');
foreach($titles as $title) { 
   $title->setAttribute("title", mb_strtoupper($title->getAttribute("title"), 'UTF-8'));
}
echo $dom->saveHTML();

参见IDEONE demo。

//a[@title] xpath获取带有属性title<a>元素(a)。

我使用mb_strtoupper假设你有UTF8输入。请进行相应的调整,或者如果您不打算使用Unicode,请使用strtoupper

更新前的原始答案

这是一个正则表达式,可以让您替换-start-end中的所有FIND子字符串:

(-start|(?!^)'G)(.*?)FIND(?=.*end-)

看到演示

$1$2NEW_WORD代替

PHP代码:

$re = "#(-start|(?!^)'G)(.*?)FIND(?=.*end-)#"; 
$str = "somes text -start bla bla FIND bla bla bla FIND bla FIND bla end-"; 
$subst = "$1$2NEW_WORD"; 
$result = preg_replace($re, $subst, $str);
echo $result;

注意:如果你有几个start-end块,你很可能需要一个调和贪婪令牌(?:(?!-start|end-|FIND).)*,而不是.*?.*

正则表达式分解:

  • (-start|(?!^)'G) -该组包含两个选项:
    • -start -匹配字符串-start
    • (?!^)'G -在最后一次成功匹配后断言原始输入字符串中的位置。'G也可以断言字符串的开头,但是我们用负正向查找排除它。
  • (.*?) -匹配任意数量的字符,但尽可能少
  • FIND -字符串FIND
  • (?=.*end-) -仅当FIND后面有文字字符串end-时。

有关'G运算符的更多信息,请参见'G何时在正则表达式中有用?

如果使用preg_replace_callback,为什么不愿意使用.*?呢?

$my_pattern = "/-start(.*?)end-/s";
$str = preg_replace_callback($my_pattern, function($matches) {
  return str_replace("FIND", "<b>FIND</b>", $matches[0]);
}, $str1.$str2);

或者在回调中做其他事情。你想达到什么目标?