Неполная замена регулярки

splashcoder

Новичок
Неполная замена регулярки

К примеру есть строка: "любой текст<text>const текст</text> другой текст ---"
Как заменить слово "текст" вне тегов <text> на "txt" к примеру?
Причем хотелось бы это сделать одной регуляркой в preg_replace, а не разбивкой текста на несколько строк.
 

splashcoder

Новичок
Логично, но как можно поставить в отрицание не набор символов (типа [^abcd]) а строку?
 

Actor

Новичок
Автор оригинала: splashcoder
Логично, но как можно поставить в отрицание не набор символов (типа [^abcd]) а строку?
ОТень пЛосто.
Я же написал, что не отрицание группы символов, а предварительный просмотр.
Для этого существуют инструкции: lookbehind assertion и lookahead assertion.
Обе они могут быть негативными.
Смотрим пример ниже:

PHP:
<?php

// Строка, в которой мы ищем
$haystack = 'любой текст<text>const текст</text> другой текст ---';

// Текст, который необходимо заменить
$needle = 'текст';

// Текст, НА КОТОРЫЙ будем заменять
$replacement = 'ИЗМЕНЕНО';

/**
 * Заменяем.
 * Не забываем про ограничители
 */
$haystack = preg_replace('{(?<!<text>)('.preg_quote($needle).')(?!</text>)}is', $replacement, $haystack);

// Смотрим
echo $haystack;

?>
 

splashcoder

Новичок
Спасибо большое за подробный ответ, но эта процедура как-то странно работает: не заменяет текст внутри тегов только если нужное слово "текст" прижато к левому или правому тегу, если
$haystack = 'любой текст<text>const текст любой </text> другой текст ---';
то почему то не работает.
В мануалах про регулярки в примерах тоже искомое выражение прижато к краю условия. Подстановки типа .+ .* не помогают. Как же сделать если строка выглядит: $haystack = 'любой текст<text>const текст любой </text> другой текст ---';
 

Вурдалак

Продвинутый новичок
Re: Неполная замена регулярки

Автор оригинала: splashcoder
Причем хотелось бы это сделать одной регуляркой в preg_replace, а не разбивкой текста на несколько строк.
— почему?
 

splashcoder

Новичок
Потому что заранее не известно сколько раз теги <text>...</text> встретятся в тексте...
Как вырезать текст обходя содержимое этих тегов я пока не придумал...
 

Вурдалак

Продвинутый новичок
PHP:
$s = 'aaa <text> bbb aaa bbb </text> aaa';
$a = preg_split('#(</?text>)#', $s, -1, PREG_SPLIT_DELIM_CAPTURE);

for($i = 0; $i < count($a); $i += 2)
	if( !(($i / 2) & 1) )
        $a[$i] = str_replace('aaa', 'ccc', $a[$i]);

$s = implode('', $a);

echo htmlspecialchars($s);
Он не учитывает вложенные теги <text>. Если нужно, то исправь сам.

-~{}~ 27.03.10 20:05:

Аналогично можно сделать и с помощью strpos (надо использовать 3-й аргумент) + substr() + str_replace() + "."

-~{}~ 27.03.10 20:06:

Форум (уже не в первый раз!) попортил код. После "</?text>" пробела нет.
 

splashcoder

Новичок
Не..., strpos не надо, и так прекрасно работает! Спасибо огромное!
Я тоже сделал с пом. preg_match_all, но у тебя всё гораздо компактнее получается и скорее всего быстрее работает...
Спасибо!
 

dimagolov

Новичок
Вурдалак, отключаешь смайлики и ничего не портиться.
PHP:
$s = 'aaa <text> bbb aaa bbb </text> aaa';
$a = preg_split('#(</?text>)#', $s, -1, PREG_SPLIT_DELIM_CAPTURE);

for($i = 0; $i < count($a); $i += 2)
    if( !(($i / 2) & 1) )
        $a[$i] = str_replace('aaa', 'ccc', $a[$i]);

$s = implode('', $a);

echo htmlspecialchars($s);
 
Сверху