正規表現エンジンが一致するネストされた構造をサポートしている場合(およびPHPがサポートしている場合)、次のように1回のパスで(ネストされている可能性のある)要素を削除できます。
1回のパスで適用される再帰正規表現:
function stripNestedElementsRecursive($text) {
return preg_replace('/
# Match outermost (nestable) "{*...*}" element.
\{\* # Element start tag sequence.
(?: # Group zero or more element contents alternatives.
[^{*]++ # Either one or more non-start-of-tag chars.
| \{(?!\*) # or "{" that is not beginning of a start tag.
| \*(?!\}) # or "*" that is not beginning of an end tag.
| (?R) # or a valid nested matching tag element.
)* # Zero or more element contents alternatives.
\*\} # Element end tag sequence.
/x', '', $text);
}
上記の再帰正規表現は、ネストされた要素を含む可能性のある最も外側 {*...*}
の要素と一致します。
ただし、正規表現エンジンがネストされた構造の一致をサポートしていない場合でも、ジョブを実行することはできますが、1回のパスで実行することはできません。最も内側 {*...*}
の要素(つまり、ネストされた要素を含まない要素)に一致する正規表現を作成できます。この正規表現は、次のようにテキストに要素がなくなるまで再帰的に適用できます。
再帰的に適用される非再帰的正規表現:
function stripNestedElementsNonRecursive($text) {
$re = '/
# Match innermost (not nested) "{*...*}" element.
\{\* # Element start tag sequence.
(?: # Group zero or more element contents alternatives.
[^{*]++ # Either one or more non-start-of-tag chars.
| \{(?!\*) # or "{" that is not beginning of a start tag.
| \*(?!\}) # or "*" that is not beginning of an end tag.
)* # Zero or more element contents alternatives.
\*\} # Element end tag sequence.
/x';
while (preg_match($re, $text)) {
$text = preg_replace($re, '', $text);
}
return $text;
}
正規表現を使用してネストされた構造を処理することは高度なトピックであり、慎重に検討する必要があります。このような高度なアプリケーションに正規表現を本当に使用したい場合は、このテーマに関する古典的な作品を読むことを強くお勧めします:ジェフリー・フリードルによる正規表現の習得(第3版) 。これは私が今まで読んだ中で最も有用な本であると正直に言うことができます。
Happy Regexing!