Разделение в строке длинных слов на короткие, кроме html тэгов. wordwrap,preg_replace

Гриша К.

Новичок
Разделение в строке длинных слов на короткие, кроме html тэгов. wordwrap,preg_replace

Здравствуйте.

Есть следующая задача: обработать переменную таким образом, чтобы все слова больше указанной длинны были разделены, например тэгом <wbr />, но с тем условием, чтобы html тэги таким образом не разделялись, а также хотелбы вообще сделать так, чтобы пробелы не заменялись на указанный символ.

Пробовал делать так, сначала применить к переменной функцию wordwrap($x, 40, '<wbr />', 1) (все делает нормально, единственной что не нравится, то что пробелы заменяются на указанный тэг, ну такова суть функции),
затем пытался при помощи preg_replace удалить тэг <wbr /> в html тэгах - это не получилось.

Это нужно для обработки сообщений на форуме, чтобы длинные слова в сообщениях не выходили за границы экрана, например длинной более 200 символов, разделяя каждые сорок символов длинного слова тэгом <wbr /> эта задача решается.

Возможно задачу можно решить при помоще уже готовых php функций, либо уже есть какие-то популярные решения такой задачи, то напишите пожалуйста об этом.

P.S. Приблизительно представляю как можно решить такую задачу, разделив переменную при помощи explode на массив используя в качестве разделителя пробел, а затем в цикле обрабатывать каждую строку, несколько пугает гомозкость такой функции, учитывая что она будет использоваться на странице много раз (15-25 - в зависимости от количества сообщений).
 

zuzmic

Новичок
Что мешает обрабатывать текст только один раз при добавлении в базу ?

PHP:
function w ($str, $max_length = 200) {
     $reg = '~\S{'.$max_length.'}\S~si';
     $replace = "$1 "; // "$1<wbr />";
     return preg_replace($reg, $replace, $str);
}


Хотя тут не проверяется на наличие тегов....
 

Гриша К.

Новичок
zuzmic, спасибо за ответ.

1) Необходима проверка на наличие тегов.
2) В базу записывать это не надо, потому что при редактировани сообщения эти тэги не нужны, только лиж при выводе сообщения нужны соотвествующие изменения.
 

fixxxer

К.О.
Партнер клуба
а откуда у тебя в хтмл тэгах неразрывный текст такой длины?
 

Гриша К.

Новичок
длинные слова в сообщениях не выходили за границы экрана, например длинной более 200 символов, разделяя каждые сорок символов длинного слова тэгом <wbr /> эта задача решается.
Я имел ввиду, что есть например слово длинной 250 символов, его необходимо разделить так, чтобы через каждые 40 символов был вставлен тэг <wbr />,
т.е. все слова длинной более 40 символов были разделены.

В html тэге, например <a href="http://..." target="_blank"> вполне легко может быть количество символов даже больше 200, при использовании длинного адреса ссылки,
поэтому ваш вопрос вообще не уместен,
я написал какая есть задача, и что я хочу ее решить, написав какой должен быть результат.
 

kruglov

Новичок
Посплитить на теги-нетеги и заменять только нетеги.

-~{}~ 11.01.08 14:38:

p.s. Другой вопрос, что некоторые теги строчные, а некоторые - нет. Т.е. строка <i>a1</i><i>a2</i>...<i>a250</i> хоть и представляет собой 250 маленьких тегов, но разрываться само по себе не будет.
 

Beavis

Banned
по-моему была такая тема
и где то в инете есть готовая функция
 

Гриша К.

Новичок
Спасибо за ответы.

kruglov
Я так понял, что посплитить вы имеете ввиду использовать функцию split, никогда ей не пользовался, щас посмотрел, попробую с ней поработать.

Beavis
Прежде чем писать на форум, я всегда пользуюсь поиском по форуму, затем ищу в инетрнете и потом пишут на форум. Те запросы которые использовал я не дали результата, ну попробую поискать еще в google готовую функцию.
 

С.

Продвинутый новичок
Зачем тратить рабочее время и вычислительны ресурсы на глупости? Если проект корпоративный,то в служебной инструкции копирайтера напосать, что слова длинее 200 букв запрещены. Если это форум, то пропускать пост с таким словом вообще не надо. Все равно в нем ничего хорошего не будет.
 

Гриша К.

Новичок
С.
Может быть пост в котором текст ссылки (фразы) будет длиннее 40 символов (это нормально), задача состоит в том чтобы фразы длиннее 40 символов разделялись (например при помощи тэга <wbr />).
Да и + к тому же, чтобы это проверить все равно нужно решить описанную выше задачу.
 

С.

Продвинутый новичок
Задача ненамного проще предыдущей.
Считать можно даже с тегами. 200 символов подряд без пробела - ненормальное явление. Урлами такой длины в публичных местах не обмениваются.
 

Гриша К.

Новичок
С.
1) Я уже второй раз поясняю о том, что должна разделяться фраза длиннее 40 символов, т.е. если фраза состоит из 200 символов, от она будет разделена 5 раз.
2) Замечание по поводу того, что "200 символов подряд без пробела - ненормальное явление", неуместно, потому что описано что есть задача, и какой должен быть результат при ее решении и + потому, что 200 символов url вполне нормальное явление, адреса ссылок бывают разыне.
3) Сложность задачи состоит в том, чтобы просто проверить переменную содержащую текст с html-тэгами на наличие фраз, кроме html тэгов, больше заданной длины.
 

FractalizeR

Новичок
Предложил бы такой вариант:

PHP:
<?php
//Case 1
$timeStarted = microtime(true);
$text = file_get_contents('test.txt');
$splitted = preg_split('/(<.+?>)/', $text, null, PREG_SPLIT_DELIM_CAPTURE+PREG_SPLIT_NO_EMPTY);
$splittedCount = count($splitted);

for($i = 0; $i < $splittedCount; $i ++) {
	if ($splitted [$i] [0] == '<') {
		continue;
	}
	$splitted [$i] = wordwrap($splitted [$i], 40, '<wbr />', true);
}
$result = implode('', $splitted);
//echo($result);
printf("%01.2f", microtime(true) - $timeStarted);
?>
На моем компе парсит 900Кб за 0.03 секунды.

Кроме того, в интернете нашел вот это: http://webcode.ru/re/br/ (Perl),
 

С.

Продвинутый новичок
Гриша К. Прошу прощения за свои неуместные замечаниями. Просто я понимаю задачу как "чтоб верстка не расползалась", а вы - "разбить по 40". Отсюда и разные решения. Копать "от забора до обеда" я уже давно отвык.
 

Гриша К.

Новичок
Спасибо за ответы.

FractalizeR, спасибо большое за пример.
Пробовал использовать функцию preg_split, но без флага PREG_SPLIT_DELIM_CAPTURE, теперь понял что это завлаг, поэтому соответвенно у меня ничего не получалось.
Переделал ваш пример, чтобы результат был такой какой мне надо.
Попробовал разобраться с функцией по ссылке, так как perl знаю очень плохо, много затруднений при переносе кода на php, решил не разбираться, а модифицировать ваш пример под себя.

С., спасибо за понимание.
Фразу - Копать "от забора до обеда" я уже давно отвык - не понял ).


Модифицировал пример приведенный FractalizeR таким образом, чтобы в результате обработки строки содержащий обычный текст и html код, возвращалась строка:
1) с сохраненными пробелами;
2) фразы больше указанной длинны разделялисm указанным разделителем (например: <wbr />);
3) фразы содержащиеся в html тэгах (<[^>]*>) не разделялись.
4) не разделенные пробелами html тэги (<b>x1</b><b>x2</b>...<b>x200</b>) разделяются указанным разделителем (например: <b>x1</b><wbr /><b>x2</b>...<b>x200</b>)

PHP:
// Функция разделения фраз больше указанной длинны, 
// кроме фраз содержащихся внутри html тэгов (<.*>)
// $str - строка, $width - максимальная длина неразделяемой строки,
// $break - разделитель
// Источник: [url]http://phpclub.ru/talk/showthread.php?postid=770750#post770750[/url]
// Вариант: [url]http://webcode.ru/re/br/[/url]
// CSS [wbr:after {content: "\00200B"}] для совместимости тэга wbr с броузерами
function wordwrap2($str, $width = '40', $break = '<wbr />')
{
	if(!$str)
		return false;	

	$str_array = preg_split('/(<[^>]*>)/', $str, null, PREG_SPLIT_NO_EMPTY+PREG_SPLIT_DELIM_CAPTURE); 

	foreach($str_array  as $key => $value) 
	{ 
		if ($value[0] == '<')
			continue;
 
		$value_array = explode(' ', $value);
		$str_array[$key] = '';
		foreach($value_array as $key2 => $value2)  
		{
			$tab = ($key2==0) ? '' : ' ';
			if(strlen($value2) > $width)
				$str_array[$key] .= $tab.wordwrap($value2, $width, $break, true);
			else
				$str_array[$key] .= $tab.$value2;
		}
	} 

	$str_array = implode('', $str_array); 
	$str_array = str_replace('><', '><wbr /><', $str_array);

	return $str_array;
}
Функцию протестировал конечно, но все может быть. Если есть что дополнить, напишите пожалуйста.


На своем форуме реализовал обработку сообщений следующим образом:
1) При добавлении и редактировании собщения обрабатываю его с помощью функции wordwrap2
2) Но в поле для ввода сообщения показываю пользователю сообщение без разделителей (например: <wbr />)
3) нет необходимости обрабатывать каждое сообщение при отображении на форуме и не смущаю пользователя разделителями.

 
Сверху