Заменить в строке символы \n на BR исключая находящиеся в блоках NOBR

fog

Рыцарь Джедай
Заменить в строке символы \n на BR исключая находящиеся в блоках NOBR

Вопрос к знатокам регулярных выражений :)

Помогите написать рег. выражение, которое в тексте заменит переносы строк на BR, кроме случаев когда перенос находится внутри блока текста, ограниченного тегами {NOBR}{/NOBR}

Я написал такой скрипт (приведён в конце), но у меня не получилось сделать это одним выражением. И вообще, то что там большой блок текста заменяется большим блоком текста мне не очень нравится. Интересно было бы посмотреть как это делается.

Можно было бы например решить это так
1. регулярным выражением заменяются все переносы строка ВНУТРИ БЛОКОВ на какой-нибудь символ(мне кажется такое рег. выражение легче будет)
2. Все оставшиеся переносы строк заменяются на <BR>
3. Символ заменяется обратно на перенос строки.

Тогда можно использовать только один регэесп.

Ещё можно менять перенос строки внутри блока на пробел, тогда обратно можно не менять вообще (так как текст после обработки будет попадать на веб-страницу, и не важно что там было - перенос строки или пробел)


мой скриптик:

PHP:
preg_match_all("/{NOBR}.*?{\/NOBR}/s", $str, $matches);

for($i=0; $i<count($matches); $i++)
{
	$str_part = str_replace("\n", "¬", $matches[$i]);
	$str = str_replace($matches[$i], $str_part, $str);
	unset($str_part);
}


$str = str_replace("\n", "<br>", $str);
$str = str_replace("¬", "\n", $str);
$str = str_replace(array('{NOBR}','{/NOBR}'), '', $str);

echo $str;
 

SiMM

Новичок
Re: Заменить в строке символы \n на BR исключая находящиеся в блоках NOBR

Автор оригинала: fog
Я написал такой скрипт (приведён в конце), но у меня не получилось сделать это одним выражением.
А зачем? Не перестают удивлять люди, которые вместо того, чтобы нормально решить проблему, начинают высасывать её из пальца и пытаются всё сделать в одно действие. Не можешь - не надо, твой случай - не тот, когда необходимы подобные изыски.
 

fog

Рыцарь Джедай
Я проблему ниоткуда не высасываю :)

Вопервых мне просто интересно можно ли это сделать одним регулярным выражением.

Вовторых, одна-две строки кода лучше чем десяток.

Может можно как-нибудь оптимизировать скрипт?
 

SiMM

Новичок
fog, по моему вам имеет смысл почитать ман по [m]preg_match_all[/m] на предмет изучения 4го параметра и константы PREG_OFFSET_CAPTURE - использовать str_replace("\n", "¬",$matches[$i]); и потом str_replace("¬", "\n", $str); на мой взгляд по крайней мере некрасиво. А использование этой фичи позволит вам делать замену только там, где нужно, а потом конкатенировать. В принципе, может и есть решение в один регулярник - может кто сообразит - но я почему-то сомневаюсь на этот счёт :)
 

fog

Рыцарь Джедай
SiMM, спасибо за наводку :) Блин, я ж специально мануал открывал посмотреть что функции ругулярных выражений умеют, как-то проглядел этот ключик :))

В общем, уже лучше получилось. Не идеал, конечно.


PHP:
function mynl2br($str)
{
	preg_match_all("/{NOBR}.*?{\/NOBR}/s", $str, $matches, PREG_OFFSET_CAPTURE);

	if (!$block_count = count($matches[0]))
	{
		return $str;
	}

	$str_result = '';
	$cursor = 0;

	for($i=0; $i < $block_count; $i++)
	{
		$str_result .= str_replace("\n", '<br>', substr($str, $cursor, $matches[0][$i][1]-$cursor)) . $matches[0][$i][0];
		$cursor = $matches[0][$i][1] + strlen($matches[0][$i][0]);
	}

	$str_result .= str_replace("\n", '<br>', substr($str, $cursor));
	$str_result = str_replace(array('{NOBR}','{/NOBR}'), '', $str_result);

	return $str_result;
}
-~{}~ 20.01.05 12:40:

А, ошибочка небольшая,

вместо

PHP:
    if (!$block_count = count($matches[0])) 
    { 
        return $str; 
    }
следует читать:

PHP:
	if (!$block_count = count($matches[0]))
	{
		return str_replace("\n", '<br>', $str);
	}
 
Сверху