Manera inteligente de truncar cadenas largas

187

¿Alguien tiene una solución / biblioteca más sofisticada para truncar cadenas con JavaScript y poner puntos suspensivos al final, que la obvia:

if (string.length > 25) {
  string = string.substring(0, 24) + "...";
}
naltatis
fuente
55
¿Qué quieres decir con "más sofisticado"? ¿Funciones que tienen en cuenta los límites de las palabras?
Residuo
2
Y no truncar en medio de las etiquetas HTML.
Sz.

Respuestas:

366

Básicamente, verifica la longitud de la cadena dada. Si es más largo que una longitud determinada n, córtelo a la longitud n( substro slice) y agregue la entidad html …(...) a la cadena recortada.

Tal método parece

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

Si por 'más sofisticado' te refieres a truncar en el límite de la última palabra de una cadena, entonces necesitas una verificación adicional. Primero recorta la cadena a la longitud deseada, luego recorta el resultado de eso a su último límite de palabra

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

Puede extender el Stringprototipo nativo con su función. En ese caso, el strparámetro debe eliminarse y strdentro de la función debe reemplazarse con 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;";
};

Más desarrolladores dogmáticos pueden capitular fuertemente sobre eso (" No modifique los objetos que no posee ". Sin embargo, no me importaría).

Un enfoque sin extender el Stringprototipo es crear su propio objeto auxiliar, que contiene la cadena (larga) que proporciona y el método mencionado anteriormente para truncarlo. Eso es lo que hace el fragmento de abajo.

Finalmente, puede usar css solo para truncar cadenas largas en nodos HTML. Le da menos control, pero puede ser una solución viable.

KooiInc
fuente
55
También debe considerar tener límites "duros" y "blandos", como, por ejemplo, si la cadena tiene más de 500 caracteres, truncala a 400. Esto puede ser útil cuando el usuario quiere ver el texto completo y hace clic en algún enlace. para ello. Si, como resultado, carga solo 1 o 2 caracteres más, se verá realmente feo.
Maxim Sloyko
2
El segundo parámetro substres una longitud, por lo que debería substr(0,n)limitarse a los primeros ncaracteres.
JohnnyHK
10
No modifique objetos que no le pertenecen. nczonline.net/blog/2010/03/02/…
Charlie Kilian
55
Una cosa que podría considerar es reemplazar el &hellip;con puntos suspensivos reales ( ...) en su ejemplo de código. Si está intentando usar esto para interactuar con las API, querrá la entidad que no sea HTML allí.
AlbertEngelB
1
@RuneJeppesen tienes razón. Ajustó los métodos. En mi defensa: la respuesta data de hace 7 años;)
KooiInc
62

Tenga en cuenta que esto solo debe hacerse para Firefox.

Todos los demás navegadores admiten una solución CSS (consulte la tabla de soporte ):

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

La ironía es que obtuve ese fragmento de código de Mozilla MDC.

mwilcox
fuente
1
mattsnider.com/css/css-string-truncation-with-ellipsis para que funcione también con FF.
Neal
Wow, esta es una solución perfecta para Safari móvil. ¡Gracias!
samvermette
9
Muy buen enfoque CSS. Puede haber una nota, que esto solo funciona con una sola línea de texto (según lo previsto por white-space: nowrap;). Cuando se trata de más de una línea, estás atrapado con JavaScript.
insertusernamehere
También solo funciona para todo el elemento. Si desea truncar parte de una cadena, sin ajustar el bit que desea truncar en un intervalo u otro elemento html, esto no funcionará, por ejemplo:Your picture ('some very long picture filename truncated...') has been uploaded.
Chris
1
OP solicitó específicamente una solución de JavaScript
vsync el
24

Hay razones válidas por las que las personas pueden desear hacer esto en JavaScript en lugar de CSS.

Para truncar a 8 caracteres (incluidos puntos suspensivos) en JavaScript:

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

o

short = long.replace(/(.{7})..+/, "$1…");
Adam Leggett
fuente
Si cuenta los puntos suspensivos, serán 9 caracteres. Si necesita que sea 8 después del truncamiento, use .replace(/^(.{7}).{2,}/, "$1…");en su lugar
Okku
longy shortestán reservadas como palabras clave futuras por especificaciones ECMAScript anteriores (ECMAScript 1 a 3). Ver MDN: Futuras palabras clave reservadas en estándares anteriores
Ricardo
9
('long text to be truncated').replace(/(.{250})..+/, "$1…");

De alguna manera, el código anterior no funcionaba para algún tipo de copia de texto pegado o escrito en la aplicación vuejs. Así que usé lodash truncate y ahora funciona bien.

_.truncate('long text to be truncated', { 'length': 250, 'separator': ' '});
Afraz Ahmad
fuente
bonita respuesta moderna!
Ykonda
Me gustaría saber cuál era el texto. ¿Estaba usando caracteres no latinos?
Adam Leggett
Fue solo un ipsum lorem
Afraz Ahmad
7

Aquí está mi solución, que tiene algunas mejoras sobre otras sugerencias:

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

Eso:

  • Se trunca en el primer espacio después de 25 caracteres.
  • Extiende el objeto String de JavaScript, por lo que se puede usar (y encadenar) en cualquier string.
  • Recortará la cadena si el truncamiento resulta en un espacio final;
  • Agregará la entidad de infierno unicode (puntos suspensivos) si la cadena truncada tiene más de 25 caracteres

fuente
7

La mejor función que he encontrado. Crédito a puntos suspensivos 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;
}

Ejemplos :

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 Hernández
fuente
5

Todos los navegadores modernos ahora admiten una solución CSS simple para agregar automáticamente puntos suspensivos si una línea de texto excede el ancho disponible:

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

(Tenga en cuenta que esto requiere que el ancho del elemento esté limitado de alguna manera para que tenga algún efecto).

Basado en https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/ .

Cabe señalar que este enfoque no se limita en función del número de caracteres. Tampoco no funciona si es necesario para permitir que múltiples líneas de texto.

Sean the Bean
fuente
2
Esto solo es útil para oraciones de una sola línea, no hay forma (hasta donde yo sé) de hacer un ejemplo de varias líneas a través de CSS.
Hooman Askari
¿Hay alguna posibilidad de que esto haga los puntos suspensivos de la izquierda en lugar de la derecha?
GreenAsJade
1
@GreenAsJade Creo que puedes lograr eso usando text-direction: rtly text-align: left. Ver davidwalsh.name/css-ellipsis-left
Sean the Bean el
4

La mayoría de los marcos JavaScript modernos ( JQuery , Prototype , etc. ) tienen una función de utilidad añadida a String que maneja esto.

Aquí hay un ejemplo en Prototype:

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

Esta parece ser una de esas funciones con las que desea que otra persona se ocupe. Dejaría que el marco lo manejara, en lugar de escribir más código.

Jim Fiorato
fuente
8
No creo que jQuery tenga nada para esto.
alex
2
Underscore.js hace - _ ('Hola mundo'). Truncate (5) => 'Hola ...' _ ('Hola'). Truncate (10) => 'Hola'
JayCrossler
3
Pure Underscore tampoco parece tenerlo truncate(); es posible que necesite una extensión como underscore.string .
Martin
2
Esta es totalmente la respuesta correcta. No sé sobre guiones bajos, pero lodash tiene lo _.truncque hace exactamente esto.
leftclickben
2
Creo que la respuesta correcta es usar lodash.trunc o underscore.string.truncate.
ooolala
2

Tal vez me perdí un ejemplo de dónde alguien está manejando nulos, pero 3 respuestas TOP no funcionaron para mí cuando tenía nulos (Claro, me doy cuenta de que el manejo de errores es y millones de otras cosas NO es responsabilidad de la persona que responde la pregunta, pero desde Había usado una función existente junto con una de las excelentes respuestas de puntos suspensivos de truncamiento que pensé que proporcionaría a otros.

p.ej

javascript:

news.comments

utilizando la función de truncamiento

news.comments.trunc(20, true);

Sin embargo, en news.comments siendo nulo esto "se rompería"

Final

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

función trunc cortesía 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_;
 };

Mi simple verificador nulo (también busca cosas "nulas" literales (esto atrapa indefinido, "", nulo, "nulo", etc.)

  function checkNull(val) {
      if (val) {
          if (val === "null") {
              return "";
          } else {
              return val;
          }
      } else {
          return "";
      }
  }
Tom Stickel
fuente
Aquí hay una versión modificada: evita el uso del prototipo, incorpora una comprobación nula en la función y tiene algún uso de prueba / demostración. codepen.io/mahemoff/pen/LGEdzy
mahemoff
¿Le parece que el prototipo es problemático? Simplemente curioso
Tom Stickel
La razón de mi función de verificación nula por separado es que realmente buscará nulo, indefinido, NaN, cadena vacía (""), 0, falso y "nulo" Pero en general me gusta su fx
Tom Stickel
1
Sí, es una cuestión de opinión y contexto de uso, pero el prototipo se pone feo cuando trabajas con otras bibliotecas, ya que también pueden anular lo mismo. (O, en casos excepcionales, una función del mismo nombre podría introducirse más adelante como una característica de lenguaje estándar)
Mahemoff
Sí, estoy de acuerdo contigo
Tom Stickel
2

A veces, los nombres de los archivos están numerados, donde el índice puede estar al principio o al final. Entonces quería acortar desde el centro de la cadena:

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

Tenga en cuenta que usé un carácter de relleno aquí con más de 1 byte en UTF-8.

Hauke
fuente
1

Voté por la solución de Kooilnc. Muy buena solución compacta. Hay un caso pequeño que me gustaría abordar. Si alguien ingresa una secuencia de caracteres realmente larga por cualquier razón, no se truncará:

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
fuente
1

Con una búsqueda rápida en Google encontré esto ... ¿Eso funciona para ti?

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

Desbordamiento de texto: puntos suspensivos es la propiedad que necesita. Con esto y un desbordamiento: oculto con un ancho específico, todo lo que supere obtendrá el efecto de tres puntos al final ... No olvide agregar espacios en blanco: ahora o el texto se colocará en varias líneas.

.wrap{
  text-overflow: ellipsis
  white-space: nowrap;
  overflow: hidden;
  width:"your desired width";
}
<p class="wrap">The string to be cut</p>
vijay kanaujia
fuente
1
La brevedad es aceptable, pero las explicaciones más completas son mejores.
Armali
mwilcox y Sean the Bean ya publicaron esta solución.
Andrew Myers
1
Solo se puede usar para texto de una línea
Vally Pepyako
El desbordamiento de texto: puntos suspensivos es perfecto !!
zardilior
0

La respuesta de c_harm es, en mi opinión, la mejor. Tenga en cuenta que si desea usar

"My string".truncate(n)

Tendrá que usar un constructor de objetos regexp en lugar de un literal. También tendrás que escapar \Sal convertirlo.

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
fuente
¿Has oído hablar de comentarios y nombres de variables adecuados?
bicicleta
@bicycle, el código se copia y modifica de otra respuesta anterior, no es necesario ser tan grosero y sarcástico.
Matt Fletcher
0

Use el siguiente código

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

Corrección de la solución de Kooilnc:

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

Esto devuelve el valor de cadena en lugar del objeto de cadena si no necesita ser truncado.

qwales1
fuente
Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar una aclaración de un autor, deje un comentario debajo de su publicación; siempre puede comentar sus propias publicaciones, y una vez que tenga suficiente reputación podrá comentar cualquier publicación .
Spencer Wieczorek
Ah, veo la distinción ahora. Gracias por las referencias. Quería dejar un comentario con la esperanza de que @Kooilnc lo viera, y posiblemente editar la respuesta aceptada si él o ella aceptaba, pero no tenía la reputación.
qwales1
0

Recientemente tuve que hacer esto y terminé con:

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

Se siente agradable y limpio para mí :)

John Doherty
fuente
1
Eso podría hacer que la cadena resultante tenga 3 caracteres más largos que el límite.
Hauke
0

Me gusta usar .slice () El primer argumento es el índice inicial y el segundo es el índice final. Todo en el medio es lo que obtienes.

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

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

En algún 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
fuente
-1

Esta función también hace el espacio truncado y las partes de palabras (ej .: Madre en Polilla ...)

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

salida:

esto es lo ...

12345 ...

Elshan
fuente