Maneira inteligente de truncar seqüências longas

187

Alguém tem uma solução / biblioteca mais sofisticada para truncar seqüências de caracteres com JavaScript e colocar reticências no final do que a óbvia:

if (string.length > 25) {
  string = string.substring(0, 24) + "...";
}
naltatis
fonte
5
O que você quer dizer com "mais sofisticado"? Funções que levam em consideração os limites das palavras?
Residuum 29/07
2
E não truncar no meio das tags HTML.
Sz.

Respostas:

366

Essencialmente, você verifica o comprimento da sequência especificada. Se for maior que um determinado comprimento n, prenda-o no comprimento n( substrou slice) e adicione a entidade html …(…) à sequência cortada.

Esse método parece

function truncate(str, n){
  return (str.length > n) ? str.substr(0, n-1) + '…' : str;
};

Se por "mais sofisticado" você quer dizer truncar no limite da última palavra de uma string, precisa de uma verificação extra. Primeiro, você recorta a string no comprimento desejado, depois recorta o resultado dela no limite da última palavra

function truncate( str, n, useWordBoundary ){
  if (str.length <= n) { return str; }
  const subString = str.substr(0, n-1); // the original check
  return (useWordBoundary 
    ? subString.substr(0, subString.lastIndexOf(" ")) 
    : subString) + "&hellip;";
};

Você pode estender o Stringprotótipo nativo com sua função. Nesse caso, o strparâmetro deve ser removido e, strdentro da função, deve ser substituído por this:

String.prototype.truncate = String.prototype.truncate || 
function ( n, useWordBoundary ){
  if (this.length <= n) { return this; }
  const subString = this.substr(0, n-1); // the original check
  return (useWordBoundary 
    ? subString.substr(0, subString.lastIndexOf(" ")) 
    : subString) + "&hellip;";
};

Mais desenvolvedores dogmáticos podem capitular você fortemente nisso (" Não modifique objetos que você não possui ". Eu não me importaria).

Uma abordagem sem estender o Stringprotótipo é criar seu próprio objeto auxiliar, contendo a cadeia (longa) fornecida e o método mencionado para truncá-lo. É isso que o trecho abaixo faz.

Por fim, você pode usar o css apenas para truncar seqüências longas em nós HTML. Dá menos controle, mas pode ser uma solução viável.

KooiInc
fonte
5
Também deve considerar limites "hard" e "soft", como, por exemplo, se a string tiver mais de 500 caracteres, truncá-la para 400. Isso pode ser útil quando o usuário deseja ver o texto inteiro e clicar em algum link por isso. Se, como resultado, você carregar apenas 1 ou 2 caracteres a mais, ficará muito feio.
Maxim Sloyko 29/07/2009
2
O segundo parâmetro para substré um comprimento, portanto, deve-se substr(0,n)limitá-lo aos primeiros ncaracteres.
JohnnyHK
10
Não modifique objetos que você não possui. nczonline.net/blog/2010/03/02/…
Charlie Kilian
5
Uma coisa que você pode considerar é substituir as &hellip;reticências reais ( ...) no seu exemplo de código. Se você estiver tentando usar isso para interagir com as APIs, precisará da entidade não HTML.
AlbertEngelB
1
@RuneJeppesen, você está certo. Ajustou os métodos. Para minha defesa: a resposta datas de 7 anos atrás;)
KooiInc
62

Observe que isso só precisa ser feito para o Firefox.

Todos os outros navegadores suportam uma solução CSS (consulte a tabela de suporte ):

p {
    white-space: nowrap;
    width: 100%;                   /* IE6 needs any width */
    overflow: hidden;              /* "overflow" value must be different from  visible"*/ 
    -o-text-overflow: ellipsis;    /* Opera < 11*/
    text-overflow:    ellipsis;    /* IE, Safari (WebKit), Opera >= 11, FF > 6 */
}

A ironia é que eu peguei esse trecho de código do Mozilla MDC.

mwilcox
fonte
1
mattsnider.com/css/css-string-truncation-with-ellipsis para fazê-lo funcionar com o FF também.
Neal
Uau, essa é uma solução perfeita para o Safari móvel. Obrigado!
21411 Samwellmette
9
Muito boa abordagem CSS. Pode haver uma observação de que isso funciona apenas com uma única linha de texto (como pretendido white-space: nowrap;). Quando se trata de mais de uma linha, você fica com o JavaScript.
usar o seguinte comando
Também funciona apenas para todo o elemento. Se você quiser parte truncada de uma corda, sem envolver o pouco que você deseja truncar em um período ou outro elemento html, isso não vai funcionar, por exemplo:Your picture ('some very long picture filename truncated...') has been uploaded.
Chris
1
OP pediu especificamente uma solução javascript
vsync
24

Existem razões válidas pelas quais as pessoas podem querer fazer isso em JavaScript, em vez de CSS.

Para truncar até 8 caracteres (incluindo reticências) em JavaScript:

short = long.replace(/(.{7})..+/, "$1&hellip;");

ou

short = long.replace(/(.{7})..+/, "$1…");
Adam Leggett
fonte
Se você contar as reticências, serão 9 caracteres. Se você precisa que ele seja 8 após truncagem, utilize .replace(/^(.{7}).{2,}/, "$1…");vez
Okku
longe shortsão reservadas como palavras-chave futuras pelas especificações mais antigas do ECMAScript (ECMAScript 1 a 3). Veja MDN: futuras palavras-chave reservadas em padrões mais antigos
Ricardo
9
('long text to be truncated').replace(/(.{250})..+/, "$1…");

De alguma forma, o código acima não estava funcionando para algum tipo de cópia colada ou texto escrito no aplicativo vuejs. Então eu usei o Lodash Truncate e agora está funcionando bem.

_.truncate('long text to be truncated', { 'length': 250, 'separator': ' '});
Afraz Ahmad
fonte
boa resposta moderna!
ykonda
Eu ficaria curioso para saber qual era o texto. Estava usando caracteres não latinos?
Adam Leggett
Foi um apenas um lorem ipsum
Afraz Ahmad
7

Aqui está minha solução, que possui algumas melhorias em relação a outras sugestões:

String.prototype.truncate = function(){
    var re = this.match(/^.{0,25}[\S]*/);
    var l = re[0].length;
    var re = re[0].replace(/\s$/,'');
    if(l < this.length)
        re = re + "&hellip;";
    return re;
}

// "This is a short string".truncate();
"This is a short string"

// "Thisstringismuchlongerthan25characters".truncate();
"Thisstringismuchlongerthan25characters"

// "This string is much longer than 25 characters and has spaces".truncate();
"This string is much longer&hellip;"

Isto:

  • Trunca no primeiro espaço após 25 caracteres
  • Estende o objeto String JavaScript, para que possa ser usado em (e acorrentado a) qualquer string.
  • Aparará a corda se o truncamento resultar em um espaço à direita;
  • Adicionará a entidade hellip unicode (reticências) se a sequência truncada tiver mais de 25 caracteres

fonte
7

Melhor função que encontrei. Crédito para reticências de texto .

function textEllipsis(str, maxLength, { side = "end", ellipsis = "..." } = {}) {
  if (str.length > maxLength) {
    switch (side) {
      case "start":
        return ellipsis + str.slice(-(maxLength - ellipsis.length));
      case "end":
      default:
        return str.slice(0, maxLength - ellipsis.length) + ellipsis;
    }
  }
  return str;
}

Exemplos :

var short = textEllipsis('a very long text', 10);
console.log(short);
// "a very ..."

var short = textEllipsis('a very long text', 10, { side: 'start' });
console.log(short);
// "...ng text"

var short = textEllipsis('a very long text', 10, { textEllipsis: ' END' });
console.log(short);
// "a very END"
Jeff Hernandez
fonte
5

Todos os navegadores modernos agora oferecem suporte a uma solução CSS simples para adicionar reticências automaticamente se uma linha de texto exceder a largura disponível:

p {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

(Observe que isso requer que a largura do elemento seja limitada de alguma forma para ter algum efeito.)

Com base em https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/ .

Note-se que essa abordagem não se limita com base no número de caracteres. Também não funciona se você precisar permitir várias linhas de texto.

Sean, o Feijão
fonte
2
Isso é útil apenas para frases de linha única, não há como (até agora eu sei) fazer um exemplo de várias linhas via CSS.
Hooman Askari 23/02
Existe por acaso uma maneira de fazer isso fazer as reticências à esquerda em vez da direita?
GreenAsJade 26/03/19
1
@GreenAsJade Eu acredito que você pode conseguir isso usando text-direction: rtle text-align: left. Veja davidwalsh.name/css-ellipsis-left
Sean the Bean
4

As estruturas Javascript mais modernas ( JQuery , Prototype , etc ...) têm uma função de utilitário anexada a String que lida com isso.

Aqui está um exemplo no Prototype:

'Some random text'.truncate(10);
// -> 'Some ra...'

Parece uma daquelas funções que você deseja que outra pessoa lide / mantenha. Eu deixaria a estrutura lidar com isso, em vez de escrever mais código.

Jim Fiorato
fonte
8
Eu não acho que o jQuery tenha algo para isso.
alex
2
O Underscore.js faz - _ ('Hello world'). Truncate (5) => 'Hello ...' _ ('Hello'). Truncate (10) => 'Hello'
JayCrossler
3
O Pure Underscore também não parece ter truncate()- você pode precisar de uma extensão como underscore.string .
martin
2
Esta é totalmente a resposta certa. Eu não sei sobre sublinhado, mas o Lodash tem o _.truncque faz exatamente isso.
leftclickben 26/03
2
Acho que a resposta certa é usar lodash.trunc ou underscore.string.truncate.
ooolala
2

Talvez eu tenha perdido um exemplo de onde alguém está lidando com nulos, mas três respostas TOP não funcionaram para mim quando eu tinha nulos. Eu tinha usado uma função existente junto com uma das excelentes respostas de reticências de truncamento que pensei que forneceria para outras pessoas.

por exemplo

javascript:

news.comments

usando a função de truncamento

news.comments.trunc(20, true);

No entanto, em news.comments ser nulo, isso "quebraria"

Final

checkNull(news.comments).trunc(20, true) 

função trunc cortesia de KooiInc

String.prototype.trunc =
 function (n, useWordBoundary) {
     console.log(this);
     var isTooLong = this.length > n,
         s_ = isTooLong ? this.substr(0, n - 1) : this;
     s_ = (useWordBoundary && isTooLong) ? s_.substr(0, s_.lastIndexOf(' ')) : s_;
     return isTooLong ? s_ + '&hellip;' : s_;
 };

Meu verificador nulo simples (verifica também a coisa "nula" literal (isso pega indefinido ",", nulo, "nulo", etc.)

  function checkNull(val) {
      if (val) {
          if (val === "null") {
              return "";
          } else {
              return val;
          }
      } else {
          return "";
      }
  }
Tom Stickel
fonte
Aqui está uma versão modificada - evita o uso de protótipo, incorpora verificação nula na função e possui algum uso de teste / demonstração. codepen.io/mahemoff/pen/LGEdzy
mahemoff
Você acha que o protótipo é problemático? Apenas curioso
Tom Stickel
A razão para a minha função de verificação nulo separado é que ele vai realmente verificar para null, indefinido, NaN, string vazia ( ""), 0, falsa e "nulo" Mas eu geral como o seu fx
Tom Stickel
1
Sim, é uma questão de opinião e contexto de uso, mas o protótipo fica feio quando você trabalha com outras bibliotecas, pois elas também podem substituir a mesma coisa. (Ou, em casos raros, uma função com o mesmo nome pode ser introduzida mais tarde como um recurso de idioma padrão.) #
1728 mahemoff
Sim, eu concordo com você
Tom Stickel
2

Às vezes, os nomes dos arquivos são numerados, onde o índice pode estar no início ou no final. Então, eu queria encurtar do centro da string:

function stringTruncateFromCenter(str, maxLength) {
    const midChar = "…";      // character to insert into the center of the result
    var left, right;

    if (str.length <= maxLength) return str;

    // length of beginning part      
    left = Math.ceil(maxLength / 2);

    // start index of ending part   
    right = str.length - Math.floor(maxLength / 2) + 1;   

    return str.substr(0, left) + midChar + str.substring(right);
}

Esteja ciente de que usei um caractere de preenchimento aqui com mais de 1 byte em UTF-8.

Hauke
fonte
1

Você pode usar a função Ext.util.Format.ellipsis se estiver usando Ext.js.

andrecardoso
fonte
1

Votei na solução do Kooilnc. Solução compacta realmente agradável. Há um pequeno caso que gostaria de abordar. Se alguém inserir uma sequência de caracteres muito longa por qualquer motivo, ela não será truncada:

function truncate(str, n, useWordBoundary) {
    var singular, tooLong = str.length > n;
    useWordBoundary = useWordBoundary || true;

    // Edge case where someone enters a ridiculously long string.
    str = tooLong ? str.substr(0, n-1) : str;

    singular = (str.search(/\s/) === -1) ? true : false;
    if(!singular) {
      str = useWordBoundary && tooLong ? str.substr(0, str.lastIndexOf(' ')) : str;
    }

    return  tooLong ? str + '&hellip;' : str;
}
backdesk
fonte
1

Com uma rápida pesquisa no Google, achei isso ... Isso funciona para você?

/**
 * Truncate a string to the given length, breaking at word boundaries and adding an elipsis
 * @param string str String to be truncated
 * @param integer limit Max length of the string
 * @return string
 */
var truncate = function (str, limit) {
    var bits, i;
    if (STR !== typeof str) {
        return '';
    }
    bits = str.split('');
    if (bits.length > limit) {
        for (i = bits.length - 1; i > -1; --i) {
            if (i > limit) {
                bits.length = i;
            }
            else if (' ' === bits[i]) {
                bits.length = i;
                break;
            }
        }
        bits.push('...');
    }
    return bits.join('');
};
// END: truncate
Manrico Corazzi
fonte
1

Estouro de texto: reticências são a propriedade que você precisa. Com isso e um estouro: oculto com uma largura específica, tudo o que ultrapassar terá o efeito de três períodos no final ... Não se esqueça de adicionar espaço em branco: nowrap ou o texto será colocado em várias linhas.

.wrap{
  text-overflow: ellipsis
  white-space: nowrap;
  overflow: hidden;
  width:"your desired width";
}
<p class="wrap">The string to be cut</p>
vijay kanaujia
fonte
1
A brevidade é aceitável, mas explicações mais completas são melhores.
Armali 26/03/19
mwilcox e Sean the Bean já publicaram esta solução.
Andrew Myers
1
Pode ser usado apenas para texto de uma linha
Vally Pepyako 01/12/19
O excesso de texto: reticências são perfeitas !!
zardilior 6/01
0

A resposta de c_harm é, na minha opinião, a melhor. Observe que se você quiser usar

"My string".truncate(n)

você precisará usar um construtor de objeto regexp em vez de um literal. Além disso, você terá que escapar \Sao convertê-lo.

String.prototype.truncate =
    function(n){
        var p  = new RegExp("^.{0," + n + "}[\\S]*", 'g');
        var re = this.match(p);
        var l  = re[0].length;
        var re = re[0].replace(/\s$/,'');

        if (l < this.length) return re + '&hellip;';
    };
Matt Fletcher
fonte
Já ouviu falar em comentários e nomeação de variáveis ​​adequada?
bicicleta
@bicycle, o código é copiado e modificado a partir de outra resposta acima, não precisa ser tão rude e sarcástico.
Matt Fletcher
0

Use o seguinte código

 function trancateTitle (title) {
    var length = 10;
    if (title.length > length) {
       title = title.substring(0, length)+'...';
    }
    return title;
}
Chathurka
fonte
0

Corrigindo a solução da Kooilnc:

String.prototype.trunc = String.prototype.trunc ||
  function(n){
      return this.length>n ? this.substr(0,n-1)+'&hellip;' : this.toString();
  };

Isso retorna o valor da string em vez do objeto String, se não precisar ser truncado.

qwales1
fonte
Isso não fornece uma resposta para a pergunta. Para criticar ou solicitar esclarecimentos a um autor, deixe um comentário abaixo da postagem - você sempre pode comentar em suas próprias postagens e, quando tiver reputação suficiente , poderá comentar em qualquer post .
Spencer Wieczorek
Ah, eu vejo a distinção agora. Obrigado pelas referências. Eu queria deixar um comentário com a esperança de que o @Kooilnc o visse e, possivelmente, editar a resposta aceita se ele concordasse, mas não tivesse reputação.
qwales1
0

Recentemente, tive que fazer isso e acabei com:

/**
 * Truncate a string over a given length and add ellipsis if necessary
 * @param {string} str - string to be truncated
 * @param {integer} limit - max length of the string before truncating
 * @return {string} truncated string
 */
function truncate(str, limit) {
    return (str.length < limit) ? str : str.substring(0, limit).replace(/\w{3}$/gi, '...');
}

Parece bom e limpo para mim :)

John Doherty
fonte
1
Isso pode fazer com que a sequência resultante seja 3 caracteres maior que o limite.
Hauke ​​31/01
0

Eu gosto de usar .slice () O primeiro argumento é o índice inicial e o segundo é o índice final. Tudo no meio é o que você recebe de volta.

var long = "hello there! Good day to ya."
// hello there! Good day to ya.

var short  = long.slice(0, 5)
// hello
Eric Wallen
fonte
0

Em algum lugar inteligente: D

//My Huge Huge String
    let tooHugeToHandle = `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).`
    
//Trim Max Length
 const maxValue = 50
// The barber.
 const TrimMyString = (string, maxLength, start = 0) => {
//Note - `start` is if I want to start after some point of the string
    	if (string.length > maxLength) {
    	let trimmedString = string.substr(start, maxLength)
    	 return (
    	   trimmedString.substr(
    	   start,
    	   Math.min(trimmedString.length,   trimmedString.lastIndexOf(' '))
           ) + ' ...'
         )
       }
    return string
}

console.log(TrimMyString(tooHugeToHandle, maxValue))

Satyam Pathak
fonte
-1

Essa função também trunca as partes do espaço e das palavras (por exemplo: Mãe na Mariposa ...)

String.prototype.truc= function (length) {
        return this.length>length ? this.substring(0, length) + '&hellip;' : this;
};

uso:

"this is long length text".trunc(10);
"1234567890".trunc(5);

resultado:

isso é lo ...

12345 ...

Elshan
fonte