Я извлекаю строку из API википедии, которая изначально выглядит так: текст ссылки . Я хочу удалить все {{…}} и все между ними (может быть любой текст). Для этого я подумал об использовании рекурсивной функции с « preg_match
», « preg_replace
». что-то вроде:
function drop_brax($text) { if(preg_match('/{{(.)*}}/',$text)) return drop_brax(preg_replace('/{{(.)*}}/','',$text)); return $text; }
Эта функция не будет работать из-за такой ситуации:
{{Мне нравится mocachino {{но мне также нравятся бананы}} и frutis}}
это отделит все, что происходит между первым вступлением как {{и}} (и оставить «и frutis}}»). Как я могу сделать это правильно? (сохраняя при этом хорошую рекурсивную форму).
Попробуйте что-то вроде этого:
$text = '...{{aa{{bb}}cc}}...{{aa{{bb{{cc}}bb{{cc}}bb}}dd}}...'; preg_match_all('/\{\{(?:[^{}]|(?R))*}}/', $text, $matches); print_r($matches);
вывод:
Array ( [0] => Array ( [0] => {{aa{{bb}}cc}} [1] => {{aa{{bb{{cc}}bb{{cc}}bb}}dd}} ) )
И короткое объяснение:
\{\{ # match two opening brackets (?: # start non-capturing group 1 [^{}] # match any character except '{' and '}' | # OR (?R) # recursively call the entire pattern: \{\{(?:[^{}]|(?R))*}} ) # end non-capturing group 1 * # repeat non-capturing group 1 zero or more times }} # match two closing brackets
для полного рекурсивного анализа вам понадобится парсер:
function drop_brax($str) { $buffer = NULL; $depth = 0; $strlen_str = strlen($str); for($i = 0; $i < $strlen_str; $i++) { $char = $str[$i]; switch ($char) { case '{': $depth++; break; case '}': $depth--; break; default: $buffer .= ($depth === 0) ? $char : NULL; } } return $buffer; } $str = 'some text {{ I like mocachino {{ but I also like banana}} and frutis }} some text'; $str = drop_brax($str); echo $str;
вывод:
some text some text