[?] Регулярное выражение

tvolf

Новичок
Добрый вечер всем.

Столкнулся с интересной проблемой. Имеется некоторая строка. Допустим,

PHP:
$str = 'текст1 текст2 < текст1 текст4 > текст3 текст1';
Необходимо в ней заменить фразу "текст1" на фразу "text1", но только те вхождения, которые не содержатся внутри угловых скобок (в данном примере необходимо заменить первое и последнее "текст1").
Попробовал использовать preg_replace(). В качестве первого параметра передаю регулярное выражение

PHP:
$regExp = "/(?:^|>).*?(текст1).*?(?:<|$)/";
Но при замене получаю в качестве результата вместо правильного варианта вот что:

PHP:
text1 текст1 текст4 text1
,

то есть, выпадают какие-то фрагменты текста.

Попробовал посмотреть, что возвращает preg_match_all() на эту строку:
Её вывод выглядит так:

PHP:
 Array
(
    [0] => Array
        (
            [0] => текст1 текст2 <
            [1] => > текст3 текст1
        )

    [1] => Array
        (
            [0] => текст1
            [1] => текст1
        )

)
То есть, кроме того, что нам нужно (находится в массиве под индексом 1), есть еще и полные вхождения выражения под индексом 0. И, видимо, именно они и используются preg_replace при замене.
Можно ли как-то этого избежать ? То есть, как исключить добавление полных выражений в результат ?
Я уже везде в тело регулярного выражения подобавлял к круглым скобкам "?:", чтобы они не включались в результат, но к самому верхнему выражению это, видимо, неприменимо.
Посоветуйте, плиз, что можно придумать ?
Заранее благодарю.
 

Splurov

Новичок
Эта задача не для регулярных выражений.
Как вариант, можно делать так:
PHP:
<?php

$t = 'текст1 текст2 < текст1 текст4 > текст3 текст1';

function replaceText($search, $replace, $t) {
	$data = array();
	$i = 0;

	$t = preg_replace_callback('/<[^>]+>/', function ($match) use (&$data, &$i) {
		$data[$i] = $match[0];
		$result = '¬' . $i . '¬';
		$i++;
		return $result;
	}, $t);

	$t = str_replace($search, $replace, $t);

	$t = preg_replace_callback('/¬(\d+)¬/', function ($match) use ($data) {
		return $data[$match[1]];
	}, $t);

	return $t;
}

echo replaceText('текст1', 'text1', $t);
 

Вурдалак

Продвинутый новичок
preg_split и смотреть на чётные (или нечётные?) элементы полученного массива.
 

tvolf

Новичок
Эта задача не для регулярных выражений.
Как вариант, можно делать так:
[... код пропущен...]
Тут главное, видимо, чтобы в тексте строки изначально не было чего-нибудь типа "¬1¬" =)
Но вообще идея понятна. Большое спасибо.
Просто думал это как-то одной командой выполнить, но вижу, что это действительно вряд ли достижимо.
 

Splurov

Новичок
craz
Какая разница какие символы? Пусть будет, например, непечатный \x06 или любой другой.
 

tvolf

Новичок
Кстати, чуть доработанный вариант:

PHP:
$t = 'текст1 текст2 < текст1 текст4 > текст3 текст1';

function replaceText2($search,$replace,$t) {
        $regExp = "/(?:^|>).*?(". preg_quote($search) .").*?(?:<|$)/"; 
	$t = preg_replace_callback($regExp, function ($match) use($search,$replace) {
	     $result = str_replace($search, $replace, $match[0]); 
             return $result;
	}, $t);
       return $t;
}
echo replaceText2('текст1', 'text1', $t);
Получилось относительно универсально (вроде бы :)
 
Сверху