Статьи

Интеллектуальное сокращение строки

В седьмой статье из серии «Маленькие и сладкие функции» я хотел бы, чтобы вы продемонстрировали вам функцию с именем abbreviate() Он сокращает строку до указанной максимальной длины, но делает это разумно — гарантирует, что разделение никогда не произойдет в середине слова, а также предварительно обрабатывает строку для удаления посторонних пробелов.

Вот abbreviate

 function abbreviate(str, max, suffix)
{
  if((str = str.replace(/^\s+|\s+$/g, '').replace(/[\r\n]*\s*[\r\n]+/g, ' ').replace(/[ \t]+/g, ' ')).length <= max)
  {
    return str;
  }
  
  var 
  abbr = '',
  str = str.split(' '),
  suffix = (typeof suffix !== 'undefined' ? suffix : ' ...'),
  max = (max - suffix.length);
  
  for(var len = str.length, i = 0; i < len; i ++)
  {
    if((abbr + str[i]).length < max)
    {
      abbr += str[i] + ' ';
    }
    else { break; }
  }

  return abbr.replace(/[ ]$/g, '') + suffix;
}

Функция принимает три аргумента — исходную строку ввода, максимальную длину вывода и необязательный суффикс, добавляемый в конец сокращенной строки. Если суффикс не определен, то по умолчанию он равен " ..."

Для чего нужна функция

Функция может использоваться всякий раз, когда вам нужно ограничить длину строки, как более разумную альтернативу простому выражению substr Существует любое количество возможных приложений — например, обработка ввода формы, создание настраиваемых всплывающих подсказок, отображение тем сообщений в веб-списке электронной почты или предварительная обработка данных для отправки через Ajax.

Например, чтобы ограничить строку до 100

 str = abbreviate(str, 100);

Что условно эквивалентно этому выражению substr

 str = str.substr(0, 96) + " ..."

Но это очень тупой инструмент, так как он часто приводит к выходной строке, которая разбивается на середину слова. Функция abbreviateперед последним словом, а не в его середине. Таким образом, выходная строка, создаваемая функцией abbreviate()короче указанного максимума, но никогда не будет длиннее .

Функция также учитывает пространство, требуемое суффиксом аббревиатуры, т.е. если конкретный максимум, если 100

Вы можете вообще не указывать суффикс, передавая пустую строку, или, если вы хотите сократить строку разметки, вы можете определить ее как закрывающий HTML -тег. Например, следующий вход:

 abbreviate("<p>One two three four five</p>", 15, "</p>");

Будет производить этот вывод:

 <p>One two</p>

Как работает функция

Ключом к abbreviate

Чтобы сделать это эффективным, нам нужно обеспечить предсказуемость разбиений между словами, и самый простой способ сделать это — минимизировать внутренние пробелы — преобразовать разрывы строк и табуляции в пробелы, а затем уменьшить непрерывные пробелы, чтобы каждый фрагмент внутренний пробел становится единым пространством. Конечно, есть и другие способы обработки — например, мы можем определить более гибкое регулярное выражение для split Для регулярных выражений есть даже символ границы слова ( "b"

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

Итак, первая задача функции — выполнить предварительную обработку пробелов, а затем, если результат уже короче указанного максимума, мы можем сразу его вернуть:

 if((str = str.replace(/^\s+|\s+$/g, '').replace(/[\r\n]*\s*[\r\n]+/g, ' ').replace(/[ \t]+/g, ' ')).length <= max)
{
  return str;
}

Если бы мы этого не делали, то мы могли бы получить случаи, когда строка сокращается, когда это необязательно, например:

 abbreviate("Already long enough", 20)

Без этого первого условия мы получили бы сокращенный вывод, поскольку указанный максимум должен учитывать длину суффикса:

 Already long ...

Принимая во внимание, что добавление этого первого условия приводит к неизмененному результату:

 Already long enough

Поэтому, если мы не вернемся в этот момент, мы приступим к компиляции сокращенной строки — разделив входную строку пробелами для создания отдельных слов, а затем итеративно добавим каждую пару слов-пространств обратно вместе, пока сокращенная строка короче указанной максимум.

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

Вывод

Итак, у вас это есть — простая, но интеллектуальная функция для сокращения строк, которая также предварительно обрабатывает ввод для удаления посторонних пробелов. По моему опыту, эти два требования часто встречаются вместе, и поэтому я разработал эту функцию для работы таким образом.