在 JavaScript 中缩短字符串而不剪切单词

我不太擅长 JavaScript 中的字符串操作,我想知道如何在不截断任何单词的情况下缩短字符串。我知道如何使用子字符串,但不是 indexOf 或任何东西真的很好。

假设我有以下字符串:

text = "this is a long string I cant display"

我想把它缩减到10个字符,但是如果没有空格结尾,就把单词写完。我不希望字符串变量看起来像这样:

“这是一条我无法描述的长线”

我想让它完成这个词,直到一个空格出现。

162387 次浏览

有很多方法可以做到这一点,但正则表达式是一种有用的单行方法:

"this is a longish string of text".replace(/^(.{11}[^\s]*).*/, "$1");
//"this is a longish"

此表达式返回前11个(any)字符加上任何后续非空格字符。

示例脚本:

<pre>
<script>
var t = "this is a longish string of text";


document.write("1:   " + t.replace(/^(.{1}[^\s]*).*/, "$1") + "\n");
document.write("2:   " + t.replace(/^(.{2}[^\s]*).*/, "$1") + "\n");
document.write("5:   " + t.replace(/^(.{5}[^\s]*).*/, "$1") + "\n");
document.write("11:  " + t.replace(/^(.{11}[^\s]*).*/, "$1") + "\n");
document.write("20:  " + t.replace(/^(.{20}[^\s]*).*/, "$1") + "\n");
document.write("100: " + t.replace(/^(.{100}[^\s]*).*/, "$1") + "\n");
</script>

产出:

1:   this
2:   this
5:   this is
11:  this is a longish
20:  this is a longish string
100: this is a longish string of text

如果我理解正确的话,你需要将一个字符串缩短到一定长度(例如,在不删除任何单词的情况下将 "The quick brown fox jumps over the lazy dog"缩短到6个字符)。

如果是这种情况,您可以尝试以下方法:

var yourString = "The quick brown fox jumps over the lazy dog"; //replace with your string.
var maxLength = 6 // maximum number of characters to extract


//trim the string to the maximum length
var trimmedString = yourString.substr(0, maxLength);


//re-trim if we are in the middle of a word
trimmedString = trimmedString.substr(0, Math.min(trimmedString.length, trimmedString.lastIndexOf(" ")))

每个人似乎都忘了 indexOf 有两个参数——要匹配的字符串和要开始查找的字符索引。可以在10个字符后的第一个空格中断字符串。

function cutString(s, n){
var cut= s.indexOf(' ', n);
if(cut== -1) return s;
return s.substring(0, cut)
}
var s= "this is a long string i cant display";
cutString(s, 10)


/*  returned value: (String)
this is a long
*/

这将排除最后一个单词,而不是包括它。

function smartTrim(str, length, delim, appendix) {
if (str.length <= length) return str;


var trimmedStr = str.substr(0, length+delim.length);


var lastDelimIndex = trimmedStr.lastIndexOf(delim);
if (lastDelimIndex >= 0) trimmedStr = trimmedStr.substr(0, lastDelimIndex);


if (trimmedStr) trimmedStr += appendix;
return trimmedStr;
}

用法:

smartTrim(yourString, 11, ' ', ' ...')
"The quick ..."

基于 NT3RP 的答案,不处理一些角落的情况下,我做了这个代码。 它保证不返回大小 > maxLlength 事件的文本,并在末尾添加了一个省略号 ...

这也可以处理一些角落情况,比如一个单词为 > maxLlength 的文本

shorten: function(text,maxLength,options) {
if ( text.length <= maxLength ) {
return text;
}
if ( !options ) options = {};
var defaultOptions = {
// By default we add an ellipsis at the end
suffix: true,
suffixString: " ...",
// By default we preserve word boundaries
preserveWordBoundaries: true,
wordSeparator: " "
};
$.extend(options, defaultOptions);
// Compute suffix to use (eventually add an ellipsis)
var suffix = "";
if ( text.length > maxLength && options.suffix) {
suffix = options.suffixString;
}


// Compute the index at which we have to cut the text
var maxTextLength = maxLength - suffix.length;
var cutIndex;
if ( options.preserveWordBoundaries ) {
// We use +1 because the extra char is either a space or will be cut anyway
// This permits to avoid removing an extra word when there's a space at the maxTextLength index
var lastWordSeparatorIndex = text.lastIndexOf(options.wordSeparator, maxTextLength+1);
// We include 0 because if have a "very long first word" (size > maxLength), we still don't want to cut it
// But just display "...". But in this case the user should probably use preserveWordBoundaries:false...
cutIndex = lastWordSeparatorIndex > 0 ? lastWordSeparatorIndex : maxTextLength;
} else {
cutIndex = maxTextLength;
}


var newText = text.substr(0,cutIndex);
return newText + suffix;
}

如果这个问题困扰您,我想您可以很容易地删除 jquery 依赖项。

我采取了不同的方法。虽然我需要一个类似的结果,我想保持我的返回值小于指定的长度。

function wordTrim(value, length, overflowSuffix) {
value = value.trim();
if (value.length <= length) return value;
var strAry = value.split(' ');
var retString = strAry[0];
for (var i = 1; i < strAry.length; i++) {
if (retString.length >= length || retString.length + strAry[i].length + 1 > length) break;
retString += " " + strAry[i];
}
return retString + (overflowSuffix || '');
}

编辑 我在这里稍微重构了它: JSFiddle 示例。它重新连接原始数组而不是连接。

function wordTrim(value, length, overflowSuffix) {
if (value.length <= length) return value;
var strAry = value.split(' ');
var retLen = strAry[0].length;
for (var i = 1; i < strAry.length; i++) {
if(retLen == length || retLen + strAry[i].length + 1 > length) break;
retLen+= strAry[i].length + 1
}
return strAry.slice(0,i).join(' ') + (overflowSuffix || '');
}

从@NT3RP 更新我发现,如果字符串碰巧击中一个空格周围的第一时间,它将最终删除该字符使您的字符串一个字短于它可以。所以我只是添加了一个 if else 语句来检查 maxLlength 是否落在一个空格上。

Codepenio

var yourString = "The quick brown fox jumps over the lazy dog"; //replace with your string.
var maxLength = 15 // maximum number of characters to extract


if (yourString[maxLength] !== " ") {


//trim the string to the maximum length
var trimmedString = yourString.substr(0, maxLength);


alert(trimmedString)


//re-trim if we are in the middle of a word
trimmedString = trimmedString.substr(0, Math.min(trimmedString.length, trimmedString.lastIndexOf(" ")))
}


else {
var trimmedString = yourString.substr(0, maxLength);
}


alert(trimmedString)
function shorten(str,n) {
return (str.match(RegExp(".{"+n+"}\\S*"))||[str])[0];
}


shorten("Hello World", 3); // "Hello"

// SHORTEN STRING TO WHOLE WORDS
function shorten(s,l) {
return (s.match(new RegExp(".{"+l+"}\\S*"))||[s])[0];
}


console.log( shorten("The quick brown fox jumps over the lazy dog", 6) ); // "The quick"

Lodash 有一个专门为此编写的函数: _.truncate

const truncate = _.truncate
const str = 'The quick brown fox jumps over the lazy dog'


truncate(str, {
length: 30, // maximum 30 characters
separator: /,?\.* +/ // separate by spaces, including preceding commas and periods
})


// 'The quick brown fox jumps...'

我有点惊讶,像这样一个简单的问题,有这么多的答案,很难阅读,有些,包括所选择的一个,不工作。

我通常希望结果字符串是 最多 maxLen字符。 我还使用同样的函数来缩短 URL 中的蛞蝓。

str.lastIndexOf(searchValue[, fromIndex]) 接受第二个参数,该参数是开始在字符串中向后搜索的索引,从而使事情变得高效和简单。

// Shorten a string to less than maxLen characters without truncating words.
function shorten(str, maxLen, separator = ' ') {
if (str.length <= maxLen) return str;
return str.substr(0, str.lastIndexOf(separator, maxLen));
}

这是一个样本输出:

for (var i = 0; i < 50; i += 3)
console.log(i, shorten("The quick brown fox jumps over the lazy dog", i));


0 ""
3 "The"
6 "The"
9 "The quick"
12 "The quick"
15 "The quick brown"
18 "The quick brown"
21 "The quick brown fox"
24 "The quick brown fox"
27 "The quick brown fox jumps"
30 "The quick brown fox jumps over"
33 "The quick brown fox jumps over"
36 "The quick brown fox jumps over the"
39 "The quick brown fox jumps over the lazy"
42 "The quick brown fox jumps over the lazy"
45 "The quick brown fox jumps over the lazy dog"
48 "The quick brown fox jumps over the lazy dog"

至于鼻涕虫:

for (var i = 0; i < 50; i += 10)
console.log(i, shorten("the-quick-brown-fox-jumps-over-the-lazy-dog", i, '-'));


0 ""
10 "the-quick"
20 "the-quick-brown-fox"
30 "the-quick-brown-fox-jumps-over"
40 "the-quick-brown-fox-jumps-over-the-lazy"

值得一提的是,我写这段代码是为了将其截断为单词边界,而不在字符串末尾留下标点符号或空格:

function truncateStringToWord(str, length, addEllipsis)
{
if(str.length <= length)
{
// provided string already short enough
return(str);
}


// cut string down but keep 1 extra character so we can check if a non-word character exists beyond the boundary
str = str.substr(0, length+1);


// cut any non-whitespace characters off the end of the string
if (/[^\s]+$/.test(str))
{
str = str.replace(/[^\s]+$/, "");
}


// cut any remaining non-word characters
str = str.replace(/[^\w]+$/, "");


var ellipsis = addEllipsis && str.length > 0 ? '&hellip;' : '';


return(str + ellipsis);
}


var testString = "hi stack overflow, how are you? Spare";
var i = testString.length;


document.write('<strong>Without ellipsis:</strong><br>');


while(i > 0)
{
document.write(i+': "'+ truncateStringToWord(testString, i) +'"<br>');
i--;
}


document.write('<strong>With ellipsis:</strong><br>');


i = testString.length;
while(i > 0)
{
document.write(i+': "'+ truncateStringToWord(testString, i, true) +'"<br>');
i--;
}

我迟到了,但这里有一个小而简单的解决方案,我想出了返回大量的话。

它不直接关系到你的要求 角色,但它服务于相同的 结果,我相信你是后。

function truncateWords(sentence, amount, tail) {
const words = sentence.split(' ');


if (amount >= words.length) {
return sentence;
}


const truncated = words.slice(0, amount);
return `${truncated.join(' ')}${tail}`;
}


const sentence = 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.';


console.log(truncateWords(sentence, 10, '...'));

请看这里的工作示例: Https://jsfiddle.net/bx7rojgl/

你可以使用下面的 truncate一行程序:

const text = "The string that I want to truncate!";


const truncate = (str, len) => str.substring(0, (str + ' ').lastIndexOf(' ', len));


console.log(truncate(text, 14));

投票结果不令人满意。所以我写了一些比较通用的东西,在文本的第一部分和最后一部分都可以使用(比如 subr,但是用于单词)。你也可以设置,如果你想要的空间被留在字符计数。

    function chopTxtMinMax(txt, firstChar, lastChar=0){
var wordsArr = txt.split(" ");
var newWordsArr = [];


var totalIteratedChars = 0;
var inclSpacesCount = true;


for(var wordIndx in wordsArr){
totalIteratedChars += wordsArr[wordIndx].length + (inclSpacesCount ? 1 : 0);
if(totalIteratedChars >= firstChar && (totalIteratedChars <= lastChar || lastChar==0)){
newWordsArr.push(wordsArr[wordIndx]);
}
}


txt = newWordsArr.join(" ");
return txt;
}

我来晚了,但我认为这个函数完全符合 OP 的要求。您可以很容易地为不同的结果更改 SENTENT 和 LIMIT 值。

function breakSentence(word, limit) {
const queue = word.split(' ');
const list = [];


while (queue.length) {
const word = queue.shift();


if (word.length >= limit) {
list.push(word)
}
else {
let words = word;


while (true) {
if (!queue.length ||
words.length > limit ||
words.length + queue[0].length + 1 > limit) {
break;
}


words += ' ' + queue.shift();
}


list.push(words);
}
}


return list;
}


const SENTENCE = 'the quick brown fox jumped over the lazy dog';
const LIMIT = 11;


// get result
const words = breakSentence(SENTENCE, LIMIT);


// transform the string so the result is easier to understand
const wordsWithLengths = words.map((item) => {
return `[${item}] has a length of - ${item.length}`;
});


console.log(wordsWithLengths);

这个代码片段的输出是 LIMIT 为11的地方:

[ '[the quick] has a length of - 9',
'[brown fox] has a length of - 9',
'[jumped over] has a length of - 11',
'[the lazy] has a length of - 8',
'[dog] has a length of - 3' ]
shorten(str, maxLen, appendix, separator = ' ') {
if (str.length <= maxLen) return str;
let strNope = str.substr(0, str.lastIndexOf(separator, maxLen));
return (strNope += appendix);

}

Var s = “这是一个很长的字符串,我无法解释所有”; 缩短(s,10,’...’)

“这是...”

边界条件如空句子和非常长的第一个单词。此外,它没有使用特定于语言的字符串 api/库。

function solution(message, k) {
if(!message){
return ""; //when message is empty
}
const messageWords = message.split(" ");
let result = messageWords[0];
if(result.length>k){
return ""; //when length of first word itself is greater that k
}
for(let i = 1; i<messageWords.length; i++){
let next = result + " " + messageWords[i];


if(next.length<=k){
result = next;
}else{
break;
}
}
return result;
}


console.log(solution("this is a long string i cant display", 10));

这里还有一段沿着 句读截断的代码(正在寻找这段代码,Google 在这里发现了这个问题)。我必须自己想出解决方案,所以这就是我在15分钟内黑进去的东西。查找所有出现的。!?并截断任何位置的这些小于 len

function pos(str, char) {
let pos = 0
const ret = []
while ( (pos = str.indexOf(char, pos + 1)) != -1) {
ret.push(pos)
}
return ret
}


function truncate(str, len) {
if (str.length < len)
return str


const allPos = [  ...pos(str, '!'), ...pos(str, '.'), ...pos(str, '?')].sort( (a,b) => a-b )
if (allPos.length === 0) {
return str.substr(0, len)
}


for(let i = 0; i < allPos.length; i++) {
if (allPos[i] > len) {
return str.substr(0, allPos[i-1] + 1)
}
}
}


module.exports = truncate

这是一行中的一个解决方案。

text = "this is a long string I cant display"


function shorten(text,max) {
return text && text.length > max ? text.slice(0,max).split(' ').slice(0, -1).join(' ') : text
}




console.log(shorten(text,10));

打字稿和省略号:)

export const sliceByWord = (phrase: string, length: number, skipEllipses?: boolean): string => {
if (phrase.length < length) return phrase
else {
let trimmed = phrase.slice(0, length)
trimmed = trimmed.slice(0, Math.min(trimmed.length, trimmed.lastIndexOf(' ')))
return skipEllipses ? trimmed : trimmed + '…'
}
}

番茄菠菜意大利面

如果你不想把单词切成两半

第一次重复:

Acc: 0/acc + cur.length = 5/newTitle = [‘ Pasta’] ;

第二次重复:

Acc: 5/acc + cur.length = 9/newTitle = [‘ Pasta’,‘ with’] ;

第三次重复:

Acc: 9/acc + cur.length = 15/newTitle = [‘ Pasta’,‘ with’,‘蕃茄’] ;

第四次重复:

Acc: 15/acc + cur.length = 18(限制界定)/newTitle = [‘ Pasta’,‘ with’,‘蕃茄’] ;

const limitRecipeTitle = (title, limit=17)=>{
const newTitle = [];
if(title.length>limit){
title.split(' ').reduce((acc, cur)=>{
if(acc+cur.length <= limit){
newTitle.push(cur);
}
return acc+cur.length;
},0);
}


return `${newTitle.join(' ')} ...`
}

产量: 西红柿意大利面..。

我们可以很容易地做到这一点,使用截断函数的 loash

_.truncate('hi-diddly-ho there, neighborino');
// => 'hi-diddly-ho there, neighbo...'


_.truncate('hi-diddly-ho there, neighborino', {
'length': 24,
'separator': ' '
});
// => 'hi-diddly-ho there,...'

请访问 Lodash 文档以获得更多清除。

下面是一个只有一行的版本,其中包含一些有用的属性:

  1. 处理与 \s正则表达式匹配的任何形式的空间
  2. 执行与输入长度无关(任何超过最大长度的内容都不会被扫描)
  3. 执行与输出长度无关的操作(从最大长度向后扫描,不拆分/连接字符串)
s.length > maxLen ? s.substring(0, s.substring(0, maxLen + 1).search(/\s+\S*$/)) : s

如果您(已经)使用了 浪荡库,那么有一个名为 截短的函数可以用来修整字符串。

基于文档页面上的示例

_.truncate('hi-diddly-ho there, neighborino', {
'length': 24,
'separator': ' '
});
// => 'hi-diddly-ho there,...'

你可以使用名为 substring的 JavaScript 方法:

var content = "ABCD";
content.substring(0, 2);
console.log(content);

预期输出为 "D"
修剪 "ABC"使可用内容为 "D"

const title = "Hello world is not the way to go"
const trimmedTitle = title.split(" ").slice(0, 4).join(" ");

//输出: “ Hello world is not”

接吻

'this is a string'.split(' ').reduce((a, b) => (a+b).length < 10 ? a+' '+b : a);