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

  • Автор темы Автор темы tvolf
  • Дата начала Дата начала

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 при замене.
Можно ли как-то этого избежать ? То есть, как исключить добавление полных выражений в результат ?
Я уже везде в тело регулярного выражения подобавлял к круглым скобкам "?:", чтобы они не включались в результат, но к самому верхнему выражению это, видимо, неприменимо.
Посоветуйте, плиз, что можно придумать ?
Заранее благодарю.
 
Эта задача не для регулярных выражений.
Как вариант, можно делать так:
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 и смотреть на чётные (или нечётные?) элементы полученного массива.
 
Эта задача не для регулярных выражений.
Как вариант, можно делать так:
[... код пропущен...]

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

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);

Получилось относительно универсально (вроде бы :)
 
Сверху