Encurtar string sem cortar palavras em JavaScript

Eu não sou muito bom com manipulação de string em JavaScript, e eu queria saber como você iria encurtar uma string sem cortar nenhuma palavra. Eu sei como usar substring, mas não indexOf ou qualquer coisa muito bem.

Digamos que eu tenha a seguinte string:

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

Eu quero reduzi-lo a 10 caracteres, mas se ele não terminar com um espaço, termine a palavra. Eu não quero que a variável de string tenha esta aparência:

“esta é uma longa corda que eu não posso dis”

Eu quero terminar a palavra até que ocorra um espaço.

Se bem entendi, você quer encurtar uma corda para um determinado comprimento (por exemplo, encurtar "The quick brown fox jumps over the lazy dog" para, digamos, 6 caracteres sem cortar qualquer palavra).

Se este for o caso, você pode tentar algo como o seguinte:

 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(" "))) 

Existem muitas maneiras de fazer isso, mas uma expressão regular é um método útil de uma linha:

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

Esta expressão retorna os primeiros 11 (quaisquer) caracteres mais quaisquer caracteres não espaciais subseqüentes.

Exemplo de script:

 
 

Saída:

 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 

Estou surpreso que, para um problema simples como este, há muitas respostas difíceis de ler e outras, inclusive a escolhida, não funcionam.

Eu geralmente quero que a string resultado seja no máximo caracteres maxLen . Eu também uso essa mesma function para encurtar as lesmas em URLs.

str.lastIndexOf(searchValue[, fromIndex]) usa um segundo parâmetro que é o índice no qual começar a pesquisar para trás na string, tornando as coisas eficientes e simples.

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

Este é um exemplo de saída:

 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" 

E para a lesma:

 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" 

Todo mundo parece esquecer que indexOf leva dois argumentos – a string para combinar e o índice de caractere para começar a procurar. Você pode quebrar a string no primeiro espaço após 10 caracteres.

 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 */ 

Lodash tem uma function especificamente escrita para isso: _.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...' 

Com base na resposta NT3RP, que não lida com alguns casos de canto, eu fiz este código. Garante não retornar um texto com um tamanho> evento maxLength que uma reticência ... foi adicionada no final.

Isso também lida com alguns casos de canto como um texto que tem uma única palavra sendo> maxLength

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

Eu acho que você pode facilmente remover a dependência jquery se isso incomoda você.

Eu tomei uma abordagem diferente. Enquanto eu precisava de um resultado semelhante, queria manter meu valor de retorno menor que o comprimento especificado.

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

Editar eu refatorei um pouco aqui: JSFiddle Example . Ele reúne o array original em vez de concatenar.

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

Isso exclui a palavra final em vez de incluí-la.

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

Uso:

 smartTrim(yourString, 11, ' ', ' ...') "The quick ..." 
 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" 

Estou atrasado para a festa, mas aqui está uma solução pequena e fácil que eu criei para retornar uma quantidade de palavras.

Não está diretamente relacionado com a sua exigência de personagens , mas serve o mesmo resultado que acredito que você estava depois.

 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, '...')); 

Veja o exemplo de trabalho aqui: https://jsfiddle.net/bx7rojgL/

Você pode aparar espaços com isso:

 var trimmedString = flabbyString.replace(/^\s*(.*)\s*$/, '$1'); 

Por que vale a pena eu escrevi isso para truncar a palavra limite sem deixar pontuação ou espaço em branco no final da string:

 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 ? '…' : ''; return(str + ellipsis); } var testString = "hi stack overflow, how are you? Spare"; var i = testString.length; document.write('Without ellipsis:
'); while(i > 0) { document.write(i+': "'+ truncateStringToWord(testString, i) +'"
'); i--; } document.write('With ellipsis:
'); i = testString.length; while(i > 0) { document.write(i+': "'+ truncateStringToWord(testString, i, true) +'"
'); i--; }

Você pode usar o truncate one-liner abaixo:

 const text = "The string that I want to truncate!"; const truncate = (str, len) => str.substring(0, (str + ' ').lastIndexOf(' ', len)); console.log(truncate(text, 14)); 

Atualizado a partir de @ NT3RP Descobri que se a string atingir um espaço na primeira vez, ela acabará excluindo a palavra, tornando a string uma palavra menor do que pode ser. Então eu apenas joguei uma instrução if else para verificar se o maxLength não cai em um espaço.

codepen.io

 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)