在 JavaScript 中换行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14484787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Wrap Text In JavaScript
提问by user2004685
I am new to JavaScript and jQuery.
我是 JavaScript 和 jQuery 的新手。
I have a variable named as strin JavaScript and it contains very long text, saying something like
我有一个str在 JavaScript 中命名为 as 的变量,它包含很长的文本,比如
"A quick brown fox jumps over a lazy dog".
I want to wrap it and assign it to the same variable strby inserting the proper \nor br/tags at the correct places.
我想str通过在正确的位置插入正确的\n或br/标签来包装它并将其分配给相同的变量。
I don't want to use CSS etc. Could you please tell me how to do it with a proper function in JavaScript which takes the strand returns the proper formatted text to it?
我不想使用 CSS 等。你能告诉我如何在 JavaScript 中使用适当的函数来实现它,该函数接受str并返回正确格式的文本吗?
Something like:
就像是:
str = somefunction(str, maxchar);
I tried a lot but unfortunately nothing turned up the way I wanted it to be! :(
我尝试了很多,但不幸的是没有像我想要的那样出现!:(
Any help will be much appreciated...
任何帮助都感激不尽...
回答by Thomas Brierley
Although this question is quite old, many solutions provided so far are more complicated and expensive than necessary, as user2257198 pointed out - This is completely solvable with a short one-line regular expression.
尽管这个问题已经很老了,但到目前为止提供的许多解决方案都比必要的复杂和昂贵,正如 user2257198 指出的那样 - 这完全可以用一个简短的单行正则表达式解决。
However I found some issues with his solution including: wrapping afterthe max width rather than before, breaking on chars not explicitly included in the character class and not considering existing newline chars causing the start of paragraphs to be chopped mid-line.
但是,我发现他的解决方案存在一些问题,包括:在最大宽度之后而不是在最大宽度之前换行,中断未明确包含在字符类中的字符,并且不考虑现有的换行符导致段落开头被截断中线。
Which led me to write my own solution:
这导致我编写了自己的解决方案:
// Static Width (Plain Regex)
const wrap = (s, w) => s.replace(
/(?![^\n]{1,32}$)([^\n]{1,32})\s/g, '\n'
);
// Dynamic Width (Build Regex)
const wrap = (s, w) => s.replace(
new RegExp(`(?![^\n]{1,${w}}$)([^\n]{1,${w}})\s`, 'g'), '\n'
);
Bonus Features
奖励功能
- Handles anychar that's not a newline (e.g code).
- Handles existing newlines properly (e.g paragraphs).
- Prevents pushing spaces onto beginning of newlines.
- Prevents adding unnecessary newline to end of string.
- 处理任何不是换行符的字符(例如代码)。
- 正确处理现有的换行符(例如段落)。
- 防止将空格推到换行符的开头。
- 防止在字符串末尾添加不必要的换行符。
Explanation
解释
The main concept is simply to find contiguous sequences of chars that do notcontain new-lines [^\n], up to the desired length, e.g 32 {1,32}. By using negation ^in the character class it is far more permissive, avoiding missing things like punctuation that would otherwise have to be explicitly added:
主要概念只是找到不包含换行符的连续字符序列[^\n],直到所需的长度,例如 32 {1,32}。通过^在字符类中使用否定,它更加宽容,避免丢失标点符号之类的东西,否则必须明确添加:
str.replace(/([^\n]{1,32})/g, '[]\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.]
"
So far this only slices the string at exactly 32 chars. It works because it's own newline insertions mark the start of each sequence after the first.
到目前为止,这只会将字符串切成 32 个字符。它起作用是因为它自己的换行插入标记了第一个序列之后的每个序列的开始。
To break on words, a qualifier is needed after the greedy quantifier {1,32}to prevent it from choosing sequences ending in the middle of a word. A word-break char \bcan cause spaces at the start of new lines, so a white-space char \smust be used instead. It must also be placed outside the group so it's eaten, to prevent increasing the max width by 1 char:
为了中断单词,在贪婪量词之后需要一个限定符,{1,32}以防止它选择以单词中间结尾的序列。换行符\b可能会在新行的开头产生空格,因此\s必须改用空白字符。它还必须放置在组外以便被吃掉,以防止将最大宽度增加 1 个字符:
str.replace(/([^\n]{1,32})\s/g, '[]\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."
Now it breaks on words before the limit, but the last word and period was not matched in the last sequence because there is no terminating space.
现在它在限制之前的单词上中断,但最后一个单词和句点在最后一个序列中不匹配,因为没有终止空格。
An "or end-of-string" option (\s|$)could be added to the white-space to extend the match, but it would be even better to prevent matching the last line at allbecause it causes an unnecessary new-line to be inserted at the end. To achieve this a negative look-ahead of exactly the same sequence can be added before, but using an end-of-string char instead of a white-space char:
可以将“或字符串结尾”选项(\s|$)添加到空格以扩展匹配,但最好完全阻止匹配最后一行,因为它会导致在结尾。为了实现这一点,可以在之前添加完全相同序列的否定前瞻,但使用字符串结尾字符而不是空白字符:
str.replace(/(?![^\n]{1,32}$)([^\n]{1,32})\s/g, '[]\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."
回答by ieeehh
This should insert a line break at the nearest whitespace of maxChar:
这应该在最近的 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));
};
回答by javabeangrinder
Here is a little shorter solution:
这是一个更短的解决方案:
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;
}
This function uses recursion to solve the problem.
该函数使用递归来解决问题。
回答by Stephan
My variant. It keeps words intact, so it might not always meet the maxChars criterium.
我的变种。它保持单词完整,因此它可能并不总是满足 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");
}
回答by cefn
Many behaviours like this can be achieved as a single-liner using regular expressions (using non-greedy quantifiers with a minimum number of matching characters, or greedy quantifiers with a maximum number of characters, depending what behaviour you need).
可以使用正则表达式(使用具有最少匹配字符数的非贪婪量词或具有最大字符数的贪婪量词,具体取决于您需要的行为)作为单行实现这样的许多行为。
Below, a non-greedy global replace is shown working within the Node V8 REPL, so you can see the command and the result. However the same should work in a browser.
下面,显示了在 Node V8 REPL 中工作的非贪婪全局替换,因此您可以看到命令和结果。然而,同样的应该在浏览器中工作。
This pattern searches for at least 10 characters matching a defined group ( \w meaning word characters, \s meaning whitespace characters), and anchors the pattern against a \b word boundary. It then uses a backreference to replace the original match with one having a newline appended (in this case, optionally replacing a space character which is not captured in the bracketed backreference).
此模式搜索至少 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, "\n")
'This is a \nparagraph \nwith several\nwords in it\n.'
In the original poster's requested format this could look like...
在原始海报要求的格式中,这可能看起来像......
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,"\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.'
回答by Fredrik Corneliusson
My version. It returns a array of lines instead of a string as it is more flexible on what line separators you want to use (like newline or html BR).
我的版本。它返回一个行数组而不是一个字符串,因为它更灵活地使用您想要使用的行分隔符(如换行符或 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;
};
To convert the line array to string to a string:
要将线数组转换为字符串再转换为字符串:
wordWrapToStringList(textToWrap, 80).join('<br/>');
Please note that it only does word wrap and will not break long words, and it's probably not the fastest.
请注意,它只进行自动换行,不会断掉长单词,而且它可能不是最快的。
回答by Joshua Olson
Here's an extended answer based on javabeangrinder's solution that also wraps text for multi-paragraph input:
这是基于 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);
}
回答by fpauer
After looking for the perfect solution using regex and other implementations. I decided to right my own. It is not perfect however worked nice for my case, maybe it does not work properly when you have all your text in Upper case.
在使用正则表达式和其他实现寻找完美的解决方案之后。我决定纠正我自己的。它并不完美,但对我来说效果很好,也许当你的所有文本都为大写时,它可能无法正常工作。
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) );
回答by Ashutosh Pathak
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("");
}
回答by Nicolas Bouvrette
Tired of regexes and hard to read functions? You can wrap texts by using built-in Arraymethods. Here is a way to do this (just replace the 100limit by your desired length:
厌倦了正则表达式和难以阅读的函数?您可以使用内置Array方法对文本进行换行。这是一种方法(只需将100限制替换为您想要的长度:
let string = '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 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(' ');
Maybe you would also like to indent this text on each line? No problem you can simply add this after the last join:
也许你还想在每一行缩进这个文本?没问题,您可以在最后一个之后简单地添加它join:
.split("\n").map(value => ''.padEnd(20) + value).join("\n");

