[英]Matching nested Patterns with Regex (using PHP's recursion)
我目前正在嘗試用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種情況可能只是一種情況[標簽不是namend“ a”],但是我聽說應該在正則表達式中避免這種情況,因為它需要環顧四周並且性能會很差。
但是,我在RegEx中看不到任何錯誤,但是它與給定的字符串不匹配。 我想要以下比賽:
<a=3>
Foo
<b>Bar</b>
</a>
Baz
這是使用RegEx的鏈接: https : //www.regex101.com/r/lO1wA6/1
您可以使用此正則表達式來匹配所需的內容(為了方便起見,將正則表達式放在字符串文字中):
'~<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]
。 匹配結束標記</\\2>
時,將捕獲標記名稱([a-zA-Z0-9]+)
和向后引用。
第二部分[^<>]++
與標記之外的其他任何內容匹配。 請注意,不對帶引號的字符串進行處理,因此根據您的輸入,它可能不起作用。
然后返回到例程調用,該例程遞歸地調用第一個捕獲組。 您會注意到,一個標簽可以包含0個或多個其他標簽或非標簽內容的實例。 由於正則表達式的編寫方式,最外面的<a=5>...</a>
對也共享此屬性。
嘗試這個:
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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.