Форматированный вывод текста: деление длинной строки

Sardonix

Новичок
Форматированный вывод текста: деление длинной строки

Уважаемые господа-программисты, имеется проблема с выводом строки.
Например, есть строка "Съешь ещё этих мягких французских булочек!
Ну, пожааааааааааааааааааааааааааааааааааааааааааааааааааалуйста!"
В этой строке все длинные лексемы (в данном случае,
"пожааааааааааааааааааааааааааааааааааааааааааааааааааалуйста!"),
т.е., лексемы, имеющие длину, больше определенной - ну, скажем,
20 символов - нужно поделить на части не более этой определенной
длины; разделителем должен быть пробел или "- " (тире с пробелом -
т.е.,эмитация переноса). Все остальные лексемы и разделяющие их
пробелы должны остаться без изменений.
Постараюсь подробно и четко описать свои действия и обрисую, с чем,
собственно, возникла проблема.

1)
PHP:
//получаю строку и очищаю ее от возможных html-тегов
$edit = strip_tags($_POST['edit']);
2)
PHP:
//проверяю пустотность строки
   if (!$edit)
      {
        echo ("Строка пуста!");
        exit();
      }
3)
PHP:
//определяю позицию первого пробела в обрабатываемой строке
   $pos = strpos($edit," ");
   if ($pos === false)
       echo ("Пробел не найден!")
   else
       echo ("Пробел в позиции ",$pos);
4)
PHP:
/* если длина подстроки от начала обрабатываемой строки до 1-го пробела
меньше или равна заданному количеству символов - копируем подстроку  в массив подстрок */
  $substr_array[$i]=substr($edit,0,$pos);
5)
PHP:
//добавляем в массив подстрок разделяющий пробел
   $substr_array[$i+1]=" ";
6)
PHP:
//удаляем скопированную подстроку из исходной строки
   $edit = substr($edit,$pos,strlen($edit));
7)
PHP:
/* если длина подстроки от начала строки или от предыдущего пробела
      до следующего пробела больше заданного количества символов - 
      делим строку */
  $substr_array[$i]=substr($edit,0,20);
8)
PHP:
//удаляем скопированную подстроку из исходной строки
   $edit = substr($edit,20,strlen($edit));
9)
PHP:
//добавляем в массив подстрок разделяющий пробел
   $substr_array[$i+1]="- ";
10)
PHP:
//объединяем все подстроки массива подстрок в единую строку
     $new_edit = join(" ",$substr_array);
NB : закон изменения : $i=0; $i=$i+2;
===============================
Объединяем всё в общий код:
_________________________


PHP:
//получаю строку и очищаю ее от возможных html-тегов
   $edit = strip_tags($_POST['edit']);

   //проверяю пустотность строки
   if (!$edit)
      {
        echo ("А строка-то пуста :( ");
        exit();
      }
   $i=0;
   while (strlen($edit) > 0)
     {

      $pos = strpos($edit," ");
      if ($pos === false)
        {
           //пробелы не найдены вообще
           //echo ("Пробел не найден!")
           $substr_array[$i] =  substr($edit,0,20);
           $substr_array[$i+1] = "- ";
           $edit = substr($edit,20,strlen($edit));
        }

      else
        {
            //пробел найден
            //echo ("Пробел в позиции ",$pos);
            if ($pos <= 20)
                {
                   //позиция пробела ближе 20 символов
                   $substr_array[$i]=substr($edit,0,$pos);
                   $substr_array[$i+1] = " ";
                   $edit = substr($edit,$pos+1,strlen($edit));

                }
            else
                {
                   //позиция пробела дальше 20 символов
                   $substr_array[$i] =  substr($edit,0,20);
                   $substr_array[$i+1] = "- ";
                   $edit = substr($edit,20,strlen($edit));

                }

        }
       $i=$i+2;
     }
  //объединяем все подстроки массива подстрок в единую строку
  @$new_edit = join(" ",$substr_array) or die ("Шут его знает где, но где-то возникла ошибка :( ");
 echo ($new_edit);
Скрипт работает - это проверено.
Вот результат его исполнения:
"Съешь ещё этих мягких французских булочек.
Ну, пожааааааааааааааааа -
аааааааааааааааааааа -
аааааааааааааалуйста - ! -"

Проблемы:
=========

1) Как вы, наверное, заметили -
в конце отформатированного текста имеется пробел и "-" - как от них избавиться?
2) Скрипт кажется мне каким-то некузявым, слишком громоздким, а известно, что некрасивое не может быть правильным.
Нельзя ли как-нибудь рацианализировать этот алгоритм с целью упрощения?
 

Sardonix

Новичок
Mr_Max, у меня нет никакой информации об этой функции.
Будь добр, дай ссылочку на информ или опиши, пжлст.
 

SiMM

Новичок
> Mr_Max, у меня нет никакой информации об этой функции.
Вообще-то существует официальный мануал.
> Будь добр, дай ссылочку на информ или опиши, пжлст.
Он дал, просто сделал это неправильно. [m]wordwrap[/m]
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
http://www.php.net/wordwrap
 

Sardonix

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

-~{}~ 14.11.05 19:25:

...wordwrap() действительно много лучше и проще обрабатывает строки, нежели то, что я там (см. выше) понагородил...
...еще одна благодарность для Mr_Max и SiMM...
 

zarus

Хитрожопый макак
PHP:
function subtract_string($str,&$pre) {
// Вспомогательная функция деления длинной непрерывной строки
// $str - строка для разбивки
// $pre - смещение от предыдущей строки
  global $divider;
  $out = '';
  // Если переданная строка - тэг, то добавляем к строке без изменения смещения
  if (preg_match('/^(<.+?>)$/si',$str)) {
    $out .= $str;
  }
  else {
    $size = strlen($str);
    // Если длина строки со смещением меньше заданной максимальной длины - добавляем без изменений и увеличиваем смещение
    if ($size <= $divider['max']-$pre) {
      $out .= $str;
      $pre += $size;
    }
    else {
      $new_len = $divider['max'] - $pre;
      // Добавляем часть строки и разделитель строк
      $out .= substr($str,0,$new_len).$divider['text'];
      $pre = 0;
      // Разбиваем оставшуюся часть строки на составляющие
      $out .= subtract_string(substr($str,$new_len),$pre);
    }
  }
  return $out;
}
function split_string($str) {
// Основная функция деления вводимой строки
  global $divider;
  $out = '';
  $pre = 0;
  // Разбиваем строку на подчасти по символам-резделителям.
  // explode(' '...) не вызывается поскольку непарные тэги могут содержать пробелы
  while (preg_match('/((?:\s|^)(?:[^\s](?:<.+?>)?)+?(?:\s|$))/si',$str,$arr)) {
    // Проверка длины подчасти строки без тэгов
    if (strlen(strip_tags($arr[1])) > $divider['max']) {
      // Разбиваем подчасть на мелкие части - массив обычных строк и тэгов.
      $var = preg_split('/(<.+?>)/si',$arr[1],-1,PREG_SPLIT_DELIM_CAPTURE);
      foreach ($var as $val) {
        $out .= subtract_string($val,$pre);
      }
      // Удаляем последний разделитель длинных строк
      $out = preg_replace('/^(.*?)'.str_replace('/','\/',($divider['text'])).'$/si','\1',$out);
    }
    else {
      $out .= $arr[1];
    }
    $str = str_replace($arr[0],'',$str);
  }
  return $out;
}

$str['in'] = 'Съешь ещё этих мягких французских булочек!<br />Ну, пожаа<b>аааааааааааааааааааааааааааааааааааа</b>ааааааааааааалуйста!';
$str['out1'] = '';
// Текст разделителя - можно подставить любой.
$divider['text'] = '-<br />';
// Максимальное количество символов, на которое будет разбиваться длинная строка
$divider['max']  = 20;

$str['out1'] = split_string($str['in']);
echo '<table border="1">';
foreach ($str as $key=>$val) {
  echo '<tr><td>'.$key.'</td><td>'.htmlentities($val,ENT_QUOTES,'cp1251').'</td></tr>';
}
echo '</table>';
word_wrap() обрезает все строки меньше заданной длины. По условию задачи - надо обрезать только длинные наборы символов, разделенные пропусками.
Если все же автор топика подразумевал именно форматирование "по ширине", тогда естественно - word_wrap и только она.
И еще, word_wrap не учитывает наличия тегов внутри текста, что при выводе в браузер даст нелицеприятный результат.

-~{}~ 14.11.05 18:33:

Изменил код - теперь он работает так, как должен. К сожалению, он не учитывает длину "недлинных строк" и не разбивает их переносами, что было бы удобнее при форматировании. Но я уверен, что при желании, скрипт можно довести до ума.
 

SelenIT

IT-лунатик :)
Похожий топик, свеженький: http://phpclub.ru/talk/showthread.php?s=&threadid=76116&rand=19
 

Sardonix

Новичок
word_wrap() обрезает все строки меньше заданной длины. По условию задачи - надо обрезать только длинные наборы символов, разделенные пропусками.
Если все же автор топика подразумевал именно форматирование "по ширине", тогда естественно - word_wrap и только она.
И еще, word_wrap не учитывает наличия тегов внутри текста, что при выводе в браузер даст нелицеприятный результат.
Изменил код - теперь он работает так, как должен. К сожалению, он не учитывает длину "недлинных строк" и не разбивает их переносами, что было бы удобнее при форматировании. Но я уверен, что при желании, скрипт можно довести до ума.
...уважаемый zarus, такой форматированный вывод я предполагаю использовать для корректного отображения длинных строк в небольшом по ширине окне чата - я уже опробовал для этой цели
PHP:
wordwrap()
и она вполне подходит (мне нужно делить только длинные лесемы в строке, т.е., основной объект не сама строка, а длинная лексема в ней + никаких тегов я в чате не предполагаю - просто вырезаю их от греха), но написанная тобой функция не пропадет втуне - это точно: я этот полезный код сохраню и при случае обязательно использую...
...большое спасибо за проявленный интерс...
 

zarus

Хитрожопый макак
Дополнение:
При вставке кода в регулярных выражениях почему-то добавился пробел. Надо заменить (<.+?> ) на (<.+?>) (т.е. без пробелов) - иначе просто работать не будет, или некорректно.
 
Сверху