34

我是 JavaScript 和 jQuery 的新手。

我有一个名为strJavaScript 的变量,它包含很长的文本,比如

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

str我想通过在正确的位置插入正确的\nbr/标签来包装它并将其分配给同一个变量。

我不想使用 CSS 等。您能否告诉我如何使用 JavaScript 中的适当函数来执行此操作,该函数接受str并返回正确的格式化文本?

就像是:

str = somefunction(str, maxchar);

我尝试了很多,但不幸的是,没有任何结果符合我的预期!:(

任何帮助都感激不尽...

4

12 回答 12

58

尽管这个问题已经很老了,但到目前为止提供的许多解决方案都比必要的复杂和昂贵,正如 user2257198 指出的那样 - 这完全可以用一个简短的单行正则表达式来解决。

但是我发现他的解决方案存在一些问题,包括:在最大宽度之后而不是之前换行,打破未明确包含在字符类中的字符,以及不考虑现有的换行符导致段落的开头被中线截断。

这导致我编写了自己的解决方案:

// Static Width (Plain Regex)
const wrap = (s) => 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'
);

奖励功能

  • 处理任何不是换行符的字符(例如代码)。
  • 正确处理现有的换行符(例如段落)。
  • 防止将空格推到换行符的开头。
  • 防止在字符串末尾添加不必要的换行符。

解释

主要概念只是找到包含 new-lines的连续字符序列[^\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."
于 2018-07-24T20:05:12.283 回答
30

这应该在 maxChar 的最近空白处插入换行符:

str = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's 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));
};
于 2013-01-23T19:05:26.893 回答
13

这是一个较短的解决方案:

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;
}

该函数使用递归来解决问题。

于 2013-01-24T13:20:18.417 回答
7

我的版本。它返回一个行数组而不是一个字符串,因为它在您想要使用的行分隔符上更灵活(如换行符或 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/>');

请注意,它只会自动换行,不会破坏长词,而且它可能不是最快的。

于 2016-08-01T23:42:22.030 回答
3

像这样的许多行为可以使用正则表达式作为单行来实现(使用具有最少匹配字符数的非贪婪量词,或具有最大字符数的贪婪量词,具体取决于您需要的行为)。

下面显示了在 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's 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\'s 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.'
于 2015-11-26T14:45:48.623 回答
2

我的变种。它保持文字完整,因此它可能并不总是符合 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");
    }
于 2014-10-09T14:48:41.823 回答
1

这是基于 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);
  }
于 2017-05-25T18:56:46.980 回答
0

在寻找使用正则表达式和其他实现的完美解决方案之后。我决定纠正我自己的。它并不完美,但对我的情况来说效果很好,当你的所有文本都是大写时,它可能无法正常工作。

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) );

于 2017-09-01T16:52:21.657 回答
-1
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("");
}
于 2013-02-06T14:28:37.940 回答
-1

我正在使用简单的 ajax 和 javascript 实践来做到这一点

var protest = "France is actually the worlds most bad country consisting of people and president full of mentaly gone persons and the people there are causing the disturbance and very much problem in the whole of the world.France be aware that one day there will be no france but you will be highly abused of your bad acts.France go to hell.";

protest = protest.replace(/(.{100})/g, "$1<br>");

document.write(protest);

于 2020-11-03T15:38:25.517 回答
-1
const newString = string.split(' ').reduce((acc, curr) => {
  if(acc[acc.length - 1].length > 100) {
    acc[acc.length - 1] = acc[acc.length - 1].concat(" ").concat(curr);
    acc.push(""); // new line
  } else {
    acc[acc.length - 1] = acc[acc.length - 1].concat(" ").concat(curr);
  }
  return acc;
}, [""]).join("\n");

console.log(newString)
于 2021-06-16T01:36:59.660 回答
-1

我知道我很晚了,但只是想分享任何评论/改进的代码。学习和即兴编写代码总是很有趣。

var text = "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).";
    
    function WordWrap(text, maxLength){
        if(!text) return 'Please provide text';
    
        const strWords = text.split(' ');
        let tempWord = ''; 
        let lineLength = 0;
    
        return strWords.reduce((acc, word) => {
            lineLength += word.length;
            
            if(lineLength > maxLength){
                lineLength = 0;
                tempWord = word;
                return `${acc} <br />`
            } else {
                const withTempWord = `${acc} ${tempWord} ${word}`;
                tempWord = '';
                return withTempWord;
            }
        }, '');
    };
    
    document.write(WordWrap(text, 14));
于 2021-06-29T02:52:27.830 回答