Обтекание текста в JavaScript

Я новичок в JavaScript и jQuery.

У меня есть переменная с именем str в JavaScript и она содержит очень длинный текст, говоря что-то вроде

"A quick brown fox jumps over a lazy dog". 

Я хочу обернуть его и присвоить его той же переменной str, вставив правильные теги \n или br/ в нужные места.

Я не хочу использовать CSS и т.д. Не могли бы вы рассказать мне, как это сделать с помощью правильной функции в JavaScript, которая принимает str и возвращает правильный форматированный текст?

Что-то вроде:

str = somefunction(str, maxchar);

Я много пробовал, но, к сожалению, ничего не оказалось так, как я хотел!: (

Любая помощь будет очень оценена...

Ответ 1

Это должно вставить разрыв строки в ближайший пробел maxChar:

str = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It w as popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";

str = wordWrap(str, 40);

function wordWrap(str, maxWidth) {
    var newLineStr = "\n"; done = false; res = '';
    while (str.length > maxWidth) {                 
        found = false;
        // Inserts new line at first whitespace of the line
        for (i = maxWidth - 1; i >= 0; i--) {
            if (testWhite(str.charAt(i))) {
                res = res + [str.slice(0, i), newLineStr].join('');
                str = str.slice(i + 1);
                found = true;
                break;
            }
        }
        // Inserts new line at maxWidth position, the word is too long to wrap
        if (!found) {
            res += [str.slice(0, maxWidth), newLineStr].join('');
            str = str.slice(maxWidth);
        }

    }

    return res + str;
}

function testWhite(x) {
    var white = new RegExp(/^\s$/);
    return white.test(x.charAt(0));
};

Ответ 2

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

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

Это заставило меня написать собственное решение:

// Static Width (Plain Regex)
const wrap = (s, w) => s.replace(
    /(?![^\n]{1,32}$)([^\n]{1,32})\s/g, '$1\n'
);

// Dynamic Width (Build Regex)
const wrap = (s, w) => s.replace(
    new RegExp('(?![^\\n]{1,${w}}$)([^\\n]{1,${w}})\\s', 'g'), '$1\n'
);

Бонусные функции

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

объяснение

Основная идея состоит в том, чтобы просто найти непрерывные последовательности символов, которые не содержат новых строк [^\n], вплоть до желаемой длины, например 32 {1,32}. Используя отрицание ^ в классе символов, он гораздо более разрешительный, избегая отсутствующих вещей, таких как пунктуация, которые в противном случае должны быть явно добавлены:

str.replace(/([^\n]{1,32})/g, '[$1]\n');
// Matches wrapped in [] to help visualise

"[Lorem ipsum dolor sit amet, cons]
[ectetur adipiscing elit, sed do ]
[eiusmod tempor incididunt ut lab]
[ore et dolore magna aliqua.]
"

Пока это только разрезает строку ровно на 32 символа. Он работает, потому что его собственные вставки новой строки отмечают начало каждой последовательности после первого.

Чтобы разбить слова, после жадного квантификатора {1,32} необходим классификатор, чтобы он не мог выбирать последовательности, заканчивающиеся в середине слова. Слово-брейк символ \b может вызвать пробела в начале новых линий, так Пробельный символ \s должен быть использован вместо. Он также должен быть помещен вне группы, чтобы он съедал, чтобы предотвратить увеличение максимальной ширины на 1 символ:

str.replace(/([^\n]{1,32})\s/g, '[$1]\n');
// Matches wrapped in [] to help visualise

"[Lorem ipsum dolor sit amet,]
[consectetur adipiscing elit, sed]
[do eiusmod tempor incididunt ut]
[labore et dolore magna]
aliqua."

Теперь он прерывается словами перед пределом, но последнее слово и период не совпадают в последней последовательности, потому что нет конечного пространства.

Опция "или конец строки" (\s|$) может быть добавлена в белое пространство, чтобы расширить совпадение, но было бы еще лучше предотвратить совпадение последней строки вообще, поскольку она вызывает ненужную новость, строка, которая будет вставлена в конец. Чтобы добиться этого, можно добавить негативный взгляд на одну и ту же последовательность, но с использованием символа конца строки вместо символа "белый пробел":

str.replace(/(?![^\n]{1,32}$)([^\n]{1,32})\s/g, '[$1]\n');
// Matches wrapped in [] to help visualise

"[Lorem ipsum dolor sit amet,]
[consectetur adipiscing elit, sed]
[do eiusmod tempor incididunt ut]
labore et dolore magna aliqua."

Ответ 3

Вот немного более короткое решение:

var str = "This is a very long line of text that we are going to use in this example to divide it into rows of maximum 40 chars."

var result = stringDivider(str, 40, "<br/>\n");
console.log(result);

function stringDivider(str, width, spaceReplacer) {
    if (str.length>width) {
        var p=width
        for (;p>0 && str[p]!=' ';p--) {
        }
        if (p>0) {
            var left = str.substring(0, p);
            var right = str.substring(p+1);
            return left + spaceReplacer + stringDivider(right, width, spaceReplacer);
        }
    }
    return str;
}

Эта функция использует рекурсию для решения проблемы.

Ответ 4

Мой вариант. Он сохраняет слова неповрежденными, поэтому он может не всегда соответствовать критерию maxChars.

function wrapText(text, maxChars) {
        var ret = [];
        var words = text.split(/\b/);

        var currentLine = '';
        var lastWhite = '';
        words.forEach(function(d) {
            var prev = currentLine;
            currentLine += lastWhite + d;

            var l = currentLine.length;

            if (l > maxChars) {
                ret.push(prev.trim());
                currentLine = d;
                lastWhite = '';
            } else {
                var m = currentLine.match(/(.*)(\s+)$/);
                lastWhite = (m && m.length === 3 && m[2]) || '';
                currentLine = (m && m.length === 3 && m[1]) || currentLine;
            }
        });

        if (currentLine) {
            ret.push(currentLine.trim());
        }

        return ret.join("\n");
    }

Ответ 5

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

Ниже приведена нежелательная глобальная замена, работающая в Node V8 REPL, поэтому вы можете увидеть команду и результат. Однако то же самое должно работать в браузере.

Этот шаблон ищет не менее 10 символов, соответствующих определенной группе (\ w означает символы слова, \s означает пробельные символы) и привязывает шаблон к границе слова \b. Затем он использует обратную ссылку, чтобы заменить исходное совпадение с добавлением новой строки (в этом случае, при необходимости заменяя пробельный символ, который не записывается в скобках с обратной связью).

> s = "This is a paragraph with several words in it."
'This is a paragraph with several words in it.'
> s.replace(/([\w\s]{10,}?)\s?\b/g, "$1\n")
'This is a \nparagraph \nwith several\nwords in it\n.'

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

var str = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It w as popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";

function wordWrap(text,width){
    var re = new RegExp("([\\w\\s]{" + (width - 2) + ",}?\\w)\\s?\\b", "g")
    return text.replace(re,"$1\n")
}

> wordWrap(str,40)
'Lorem Ipsum is simply dummy text of the\nprinting and typesetting industry. Lorem Ipsum has been the industry\ standard dummy text ever since the 1500s\n, when an unknown printer took a galley of\ntype and scrambled it to make a type specimen\nbook. It has survived not only five centuries\n, but also the leap into electronic typesetting\n, remaining essentially unchanged. It w as popularised in the 1960s with the\nrelease of Letraset sheets containing Lorem\nIpsum passages, and more recently with desktop publishing\nsoftware like Aldus PageMaker including\nversions of Lorem Ipsum.'

Ответ 6

Моя версия. Он возвращает массив строк вместо строки, поскольку он более гибкий в том, какие разделители строк вы хотите использовать (например, newline или html BR).

function wordWrapToStringList (text, maxLength) {
    var result = [], line = [];
    var length = 0;
    text.split(" ").forEach(function(word) {
        if ((length + word.length) >= maxLength) {
            result.push(line.join(" "));
            line = []; length = 0;
        }
        length += word.length + 1;
        line.push(word);
    });
    if (line.length > 0) {
        result.push(line.join(" "));
    }
    return result;
};

Чтобы преобразовать массив строк в строку в строку:

wordWrapToStringList(textToWrap, 80).join('<br/>');

Обратите внимание, что это только перенос слов и не прерывает длинные слова, и это, вероятно, не самый быстрый.

Ответ 7

Здесь расширенный ответ на основе решения javabeangrinder, который также обертывает текст для ввода с несколькими параграфами:

  function wordWrap(str, width, delimiter) {
    // use this on single lines of text only

    if (str.length>width) {
      var p=width
      for (; p > 0 && str[p] != ' '; p--) {
      }
      if (p > 0) {
        var left = str.substring(0, p);
        var right = str.substring(p + 1);
        return left + delimiter + wordWrap(right, width, delimiter);
      }
    }
    return str;
  }

  function multiParagraphWordWrap(str, width, delimiter) {
    // use this on multi-paragraph lines of text

    var arr = str.split(delimiter);

    for (var i = 0; i < arr.length; i++) {
        if (arr[i].length > width)
          arr[i] = wordWrap(arr[i], width, delimiter);
    }

    return arr.join(delimiter);
  }

Ответ 8

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

function breakTextNicely(text, limit, breakpoints) {

      var parts = text.split(' ');
      var lines = [];
      text = parts[0];
      parts.shift();

      while (parts.length > 0) {
        var newText = `${text} ${parts[0]}`;

        if (newText.length > limit) {
          lines.push(`${text}\n`);
          breakpoints--;

          if (breakpoints === 0) {
            lines.push(parts.join(' '));
            break;
          } else {
          	text = parts[0];
    	  }
        } else {
          text = newText;
        }
    	  parts.shift();
      }

      if (lines.length === 0) {
        return text;
      } else {
        return lines.join('');
      }
    }

    var mytext = 'this is my long text that you can break into multiple line sizes';
    console.log( breakTextNicely(mytext, 20, 3) );

Ответ 9

function GetWrapedText(text, maxlength) {    
    var resultText = [""];
    var len = text.length;    
    if (maxlength >= len) {
        return text;
    }
    else {
        var totalStrCount = parseInt(len / maxlength);
        if (len % maxlength != 0) {
            totalStrCount++
        }

        for (var i = 0; i < totalStrCount; i++) {
            if (i == totalStrCount - 1) {
                resultText.push(text);
            }
            else {
                var strPiece = text.substring(0, maxlength - 1);
                resultText.push(strPiece);
                resultText.push("<br>");
                text = text.substring(maxlength - 1, text.length);
            }
        }
    }
    return resultText.join("");
}

Ответ 10

Устали от регулярных выражений и трудно читаемых функций? Вы можете обернуть тексты, используя встроенные методы Array. Вот как это сделать (просто замените предел 100 на нужную длину:

let string = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\ standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.';

string.split(' ').map((value, index, array) => {
    if (!array.currentLineLength) {array.currentLineLength = 0}
    array.currentLineLength += value.length+1;
    if (array.currentLineLength > 100) {
        array.currentLineLength = value.length;
        return "\n" + value;
    }
    return value;
}).join(' ');

Может быть, вам также хотелось бы отложить этот текст на каждой строке? Нет проблем, вы можете просто добавить это после последнего join:

.split("\n").map(value => ''.padEnd(20) + value).join("\n");