За последние 24 часа нас посетили 17555 программистов и 1719 роботов. Сейчас ищет 1781 программист ...

Как обрезать текст по границам слов

Тема в разделе "PHP для новичков", создана пользователем ricciotto, 23 авг 2007.

  1. ricciotto

    ricciotto Активный пользователь

    С нами с:
    23 авг 2007
    Сообщения:
    6
    Симпатии:
    0
    Подскажите, плз, как обрезать текст, задав максимальное количество символов, но при этом не обрезая слова. Нужно сделать анонс новости на главной странице (кусок текста новости).
     
  2. basist

    basist Активный пользователь

    С нами с:
    7 июл 2007
    Сообщения:
    388
    Симпатии:
    0
    Адрес:
    Орел
    наверное как-то так:


    $максимальное кол-во символов = 100;

    $строка = substr($строка, 0, $максимальное кол-во символов);
    $конец строки = strlen(строка);
    пока (строка[$конец строки] !== " "){

    $строка = substr($строка, 0, strlen($строка)-1)

    }

    echo $str . "...";
     
  3. basist

    basist Активный пользователь

    С нами с:
    7 июл 2007
    Сообщения:
    388
    Симпатии:
    0
    Адрес:
    Орел
    не, этот вариант плохой.. лучше так:
    (хотя и криво, понимаю...)


    PHP:
    1.  
    2. <?php
    3. Error_Reporting(E_ALL & ~E_NOTICE);
    4. $max = 50;
    5. $str = 'новость дня новость дняновость дняновостьдняновость дняновостьдняновостьдня';
    6. echo "исходная строка: <br>" . $str . "<br>";
    7. $n = strlen($str);
    8. $m = 0;
    9. while ($str[$n] !== " ") {
    10. $m+=1;
    11. $n-=1;
    12. };
    13.  
    14. $str = substr($str,0,strlen($str)-$m);
    15. echo "обрезанная строка: <br>" . $str;
    16. ?>
    17.  
     
  4. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    самый правильный подход - завести поле "анонс" и вписыывать туда нужный текст...

    учить до просветления.
    http://www.artlebedev.ru/kovodstvo/98/
     
  5. Anonymous

    Anonymous Guest

    О! Холивар! ;)

    Я против дубляжа текста при наборе. (Но не против - в базе)
    Предлагаю ставить метку в основном тексте, откусывать анонс и класть в базу.
     
  6. ricciotto

    ricciotto Активный пользователь

    С нами с:
    23 авг 2007
    Сообщения:
    6
    Симпатии:
    0
    Точно, это - дополнительный объем работы.

    А как это реализовать?
     
  7. Veem

    Veem Активный пользователь

    С нами с:
    21 авг 2007
    Сообщения:
    76
    Симпатии:
    0
    Пишете ваш длинный текст, неожиданно в середине ставите какой-нибудь символ/комбинацию, при выводе в анонс - отрываете кусок до нее, при выводе куда надо - удаляете символ/комбинацию. Это если весь текст хранить в одной ячейке таблицы БД.
    Или же поступаете аналогично, при наборе текста точно так же указываете метку, при нажатии кнопки "Отправить/Послать/Что-там-еще" отгрызаете все до метки - это заносится в столбец "анонс", а все, что после метки, заносите в другой столбец. При выводе анонса выбираете из таблицы только анонс, при выводе всего текста - анонс + текст, соединяете их и выводите в удобном вам виде. Или не соединяете, тут уже все в ваших руках. И никакого дублирования в процессе.
     
  8. Anonymous

    Anonymous Guest

    Вариант попроще - брать первый параграф.
    Вариант посложнее - сделать какой либо тег разметки для откусывания. + еще и для формирования текста на полную новость.
     
  9. ricciotto

    ricciotto Активный пользователь

    С нами с:
    23 авг 2007
    Сообщения:
    6
    Симпатии:
    0
    Спасибо, тоже попробую. Кажется, нашла простой выход:

    PHP:
    1.  
    2. <?php
    3. $str = "Темпы роста рынка электронных платежных систем России замедлились в 2006 г.";
    4. echo "ИЗНАЧАЛЬНАЯ СТРОКА: " . $str . "<br><br>";
    5. $length = 20; // Максимальная длина обрезанной строки
    6. do {
    7. substr($str,$length,1);
    8. $length = $length - 1;
    9. }
    10. while (substr($str,$length,1) !== " ");
    11. $str_cut = substr($str,0,$length);
    12. echo "ОБРЕЗАННАЯ СТРОКА: " . $str_cut;
    13. ?>
     
  10. Veem

    Veem Активный пользователь

    С нами с:
    21 авг 2007
    Сообщения:
    76
    Симпатии:
    0
    Вы прочитали информацию по этой ссылке?
     
  11. ricciotto

    ricciotto Активный пользователь

    С нами с:
    23 авг 2007
    Сообщения:
    6
    Симпатии:
    0
  12. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    будем уважать своих посетителей или пофиг - все равно прочтут?

    это как ссылки делать в новостях. или выделять весь параграф или помечать отдельные слова в заголовке.
     
  13. ricciotto

    ricciotto Активный пользователь

    С нами с:
    23 авг 2007
    Сообщения:
    6
    Симпатии:
    0
    440Hz,
    вариант с меткой лично мне кажется менее трудоемким, чем дублирование информации.
     
  14. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    инфор мацию будут забивать операторы, а не вы.

    метка тоже вариант.
     
  15. ricciotto

    ricciotto Активный пользователь

    С нами с:
    23 авг 2007
    Сообщения:
    6
    Симпатии:
    0
    440Hz,
    оператору тоже нужно помочь. Хотя посетитель, безусловно, на первом месте.
     
  16. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    PHP:
    1. <?php
    2. define ('MAX_WIDTH', 20);
    3. $str = "тут такая строка очень длинная...";
    4. if (strlen ($str) > MAX_WIDTH)
    5.     $str = substr ($str, 0, MAX_WIDTH-strlen (strrchr (substr ($str, 0, MAX_WIDTH), ' ')));
    6. echo "#$str#";
    7. ?>
    как-то вот так получилось... 4 вызова... можно ещё попробовать с wordwrap, но это в качестве самостоятельного упражнения.
     
  17. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    А тем временем, Дима Смирнов рулит аж с 1998-ого года :).
    PHP:
    1. $txt = 'Переменная с текстом';
    2. preg_match("/.{150}[^.!;?]*[.!;?]/si", $txt.". ", $matches);
    3. $txt=$matches[0];
     
  18. DarkElf

    DarkElf Активный пользователь

    С нами с:
    22 окт 2006
    Сообщения:
    1.632
    Симпатии:
    0
    может так..

    PHP:
    1. <?php
    2. echo implode(array_slice(explode('<br>',wordwrap($text,$lenght,'<br>',false)),0,1));
    3. ?>
    собственно, алгоритм работы:

    1) wordwrap без разделения слов разбивает строку $text на элементы длиной $lenght с разделителем '<br>'.

    2) explode разбивает полученную на этапе 1 строку на массив по элементу <br>

    3) array_slice из полученного массива возвращает массив, состоящий из элементов исходного, начиная с 0, в кол-ве 1, то есть первую строку.

    4) implode выпрямляет полученный массив с 1 элементом в строку

    5) echo выплевывает строку в поток вывода.
     
  19. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    ну, где-то так. только если по-хорошему делать, $text надо ещё предварительно пропустить через htmlspecialchars, чтобы убрать маркер (если в тексте уже есть <br>, он собьёт разделение).

    по-любому, не менее четырёх вызовов, из которых три -- на массивах.
     
  20. DarkElf

    DarkElf Активный пользователь

    С нами с:
    22 окт 2006
    Сообщения:
    1.632
    Симпатии:
    0
    маркет другим сделать... и trim добавить..
    чтоб теги потом не восстанавливать
     
  21. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    lexa
    принцип ясен, но это немного не то. в вашем с димой случае вы получаете предложение (строку, оканчивающуюся символами .!;?), длиной не менее 150 символов. задача ставилась немного другая. используя реги я бы на вашем с димой месте написал так:
    /^.{,150}\W/
     
  22. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    стоят ли все эти "програмистские изыски" одно поля в табличке и такого же в форме куда знающий редактор/оперетор поместит именно тот текст, который наиболее подходит и по размеру и по содержанию?

    ИМХО - нет.
    ИМХО муйней маетесь товарищи.
     
  23. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    440Hz
    а если этого поля нет? например, вы получаете новостную строку и хотите отобразить только её начало?
     
  24. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    в данном конкретном случае придется извращаться.
     
  25. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    в общем так. зацепило меня этим примером. решил поэкспериментировать. сделал замеры. и вот что у меня нарисовалось (я позволил себе чуток модифицировать приведённые примеры дабы выжать из них по максимуму).

    постановка задачи
    определить относительную производительность четырёх предложенных вариантов решения задачи об усечении длинной строки по границе слова. производительность замеряется относительно операции присваивания данной строки локальной переменной.

    итак
    строка (375 символов):
    Код (Text):
    1. $str = 'Here we got a very very long string which is repeated multiple times to produce a more native look of a news line paragraph. Here we got a very very long string which is repeated multiple times to produce a more native look of a news line paragraph. Here we got a very very long string which is repeated multiple times to produce a more native look of a news line paragraph.';
    эталонный код:
    Код (Text):
    1. $a = $str;
    код №1 (принцип -- вручную ищем первый пробел в строке начиная с позиции MAX_WIDTH по направлению к началу):
    Код (Text):
    1. for ($length = MAX_WIDTH
    2.     ; $str[$length] !== ' ' and $length
    3.     ; $length--
    4.     );
    5. $a = substr ($str, 0, $length);
    код №2 (принцип -- делаем то же самое, но при помощи встроенных функций):
    Код (Text):
    1. $a = substr ($str, 0, MAX_WIDTH-strlen (strrchr (substr ($str, 0, MAX_WIDTH), ' ')));
    код №3 (принцип -- используя встроенную функцию wordwrap делим строку, ограничивая подстроки маркером. после этого при помощи explode извлекаем первую подстроку. перед вызовом wordwrap удаляем лишнее, чтобы не хранить слишком много такста):
    Код (Text):
    1. list ($a) = explode ('<br>', wordwrap (substr ($str, 0, MAX_WIDTH+1), MAX_WIDTH, '<br>', false));
    код №4 (регулярка берёт первые MAX_WIDTH символов от начала строки и откатывается назад до первого не-буквенного символа):
    Код (Text):
    1. preg_match ('/^.{0,'.MAX_WIDTH.'}\W/', $str, $matches);
    2. $a = substr ($matches[0], 0, -1);
    итоги конкурса:
    Код (Text):
    1. bench name: wordwrap first N characters
    2.  empty  :  1.00
    3. snippet1:  6.17
    4. snippet2:  5.70
    5. snippet3:  8.27
    6. snippet4:  8.85
    7.  
    8. total time: 21.19 sec.
    9. php ver: 4.4.7
    10. os: Darwin
    или если выражаться картинно:
    Код (Text):
    1. 0: *
    2. 1: ******
    3. 2: *****-
    4. 3: ********-
    5. 4: *********
    выводы:
    1/ разброс значений не такой уж и большой. несмотря на то, что регулярка (самое тяжёлое решение) в полтора раза тяжелее кода №2 я склоняюсь к тому, что в скромном проекте (не требующем выжимать максимума из кода) использовать надо именно её, потому как нагляднее.
    2/ приятно порадовал код №1 с ручным поиском. твёрдое второе место по производительности.

    при желании могу выложить код для замера производительности дабы не быть голословным