我目前正在尝试在PHP中编写一个正则表达式,它允许我匹配一个包含自身的特定模式,这些模式是无限制嵌套的。我知道默认的正则表达式无法做到这一点,但PHP的递归模式(http://php.net/manual/de/regexp.reference.recursive.php)应该可以实现。
我有这样的嵌套结构:
<a=5>
<a=3>
Foo
<b>Bar</b>
</a>
Baz
</a>
现在我想匹配最外面标签的内容。为了正确匹配第一个开始标记和最后一个结束标记,我需要PHP的递归项(?R)
。
我尝试了这样的模式:
/<a=5>((?R)|[^<]|<\/?[^a]|<\/?a[a-zA-Z0-9-])*<\/a>/s
这基本上意味着<a=5>
,然后是尽可能多的以下内容,然后是</a>
:
最后2个案例可能只是一个案例[标签不是名字&#34; a&#34;],但我听说在正则表达式中应该避免这种情况,因为它需要外观并且会有糟糕的表现。
但是,我在RegEx中看到没有错误,但它与给定的字符串不匹配。我想要以下比赛:
<a=3>
Foo
<b>Bar</b>
</a>
Baz
以下是使用RegEx的链接:https://www.regex101.com/r/lO1wA6/1
答案 0 :(得分:2)
你可以使用这个正则表达式来匹配你想要的东西(为方便起见,将正则表达式放在一个字符串文字中):
'~<a=5>(<([a-zA-Z0-9]+)[^>]*>(?1)*</\2>|[^<>]++)*</a>~'
以上是正则表达式的细分:
<a=5>
(
<([a-zA-Z0-9]+)[^>]*>
(?1)*
</\2>
|
[^<>]++
)*
</a>
第一部分<([a-zA-Z0-9]+)[^>]*>(?1)*</\2>
匹配一对匹配标记及其所有内容。它假定标记的名称由字符[a-zA-Z0-9]
组成。在匹配结束标记([a-zA-Z0-9]+)
时,会捕获标记的名称</\2>
和反向引用。
第二部分[^<>]++
匹配标记之外的任何其他内容。请注意,没有处理带引号的字符串,因此根据您的输入,它可能无效。
然后回到递归调用第一个捕获组的例程调用。您会注意到标记可以包含0个或更多其他标记或非标记内容的实例。由于正则表达式的编写方式,此属性也由最外面的<a=5>...</a>
对共享。
答案 1 :(得分:-1)
试试这个:
<强> PHP 强>
$re = "/(<[^\\/>]+(\\/?)>)*([^<]+)(<\\/\\w+>)*/m";
$str = "<a=5>\n <a=3>\n Foo\n <b/>Bar</b>\n </a>\n Baz\n</a>";
preg_match_all($re, $str, $matches);
var_dump($matches);
// here
$matches[1]; //for open tag array
$matches[2]; //for single tag mark array by ( />)
$matches[3]; //for inner data array
$matches[4]; //for close tag array
<强>输出强>
array (size=5)
0 =>
array (size=5)
0 => string '<a=5>
' (length=7)
1 => string '<a=3>
Foo
' (length=12)
2 => string '<b/>Bar</b>' (length=11)
3 => string '
</a>' (length=6)
4 => string '
Baz
</a>' (length=10)
1 =>
array (size=5)
0 => string '<a=5>' (length=5)
1 => string '<a=3>' (length=5)
2 => string '<b/>' (length=4)
3 => string '' (length=0)
4 => string '' (length=0)
2 =>
array (size=5)
0 => string '' (length=0)
1 => string '' (length=0)
2 => string '/' (length=1)
3 => string '' (length=0)
4 => string '' (length=0)
3 =>
array (size=5)
0 => string '
' (length=2)
1 => string '
Foo
' (length=7)
2 => string 'Bar' (length=3)
3 => string '
' (length=2)
4 => string '
Baz
' (length=6)
4 =>
array (size=5)
0 => string '' (length=0)
1 => string '' (length=0)
2 => string '</b>' (length=4)
3 => string '</a>' (length=4)
4 => string '</a>' (length=4)
或强>
$re = "/(<[^\\/>]+\\/?>)*([^<]+)(<\\/\\w+>)*/m";
$str = "<a=5>fff\n <a=3>\n Foo\n <b/>Bar</b>\n </a>\n Baz\n</a>";
preg_match_all($re, $str, $matches);
//var_dump($matches);
$md="";
$c=count($matches[1]);
foreach($matches[1] as $k=>$v){
if($k!=0){
$md.=$v.$matches[2][$k].$matches[3][$k];
}
else if ($c!=$k+1){
$md.=$matches[2][$k].$matches[3][$k];
}
}
var_dump($md);
<强>输出强>
string 'fff
<a=3>
Foo
<b/>Bar</b>
</a>
Baz
</a>' (length=44)