2008-10-30 9 views
37

Estoy buscando una manera de truncar una cadena en Python que no corte la cadena en el medio de una palabra.Truncar una cadena sin terminar en el medio de una palabra

Por ejemplo:

 
Original:   "This is really awesome." 
"Dumb" truncate: "This is real..." 
"Smart" truncate: "This is really..." 

Busco una manera de lograr la "inteligente" truncar desde arriba.

Respuesta

56

De hecho, escribí una solución para esto en un proyecto mío reciente. He comprimido la mayor parte para ser un poco más pequeño.

def smart_truncate(content, length=100, suffix='...'): 
    if len(content) <= length: 
     return content 
    else: 
     return ' '.join(content[:length+1].split(' ')[0:-1]) + suffix 

Lo que ocurre es que la instrucción if comprueba si su contenido ya es inferior al punto de corte. Si no es así, se trunca en la longitud deseada, se divide en el espacio, elimina el último elemento (para que no se corte una palabra) y luego vuelve a unirse (mientras se marca el '...') .

+0

Esto es muy concisa ... me gustaría añadir una prueba más para evitar las cadenas vacías en caso de que no existen espacios en absoluto en los primeros caracteres de "longitud". – Jonas

+5

El truncamiento tuvo que considerar la longitud del sufijo: 'return '' .join (content [: length + 1-len (sufijo)]. Split ('') [0: -1]) + sufijo ' – Stan

43

Aquí hay una versión ligeramente mejorada de la última línea en la solución de Adán:

return content[:length].rsplit(' ', 1)[0]+suffix 

(Esta cifra es ligeramente más eficiente, y devuelve un resultado más sensible en el caso de que no haya espacios en la parte delantera de la cadena .)

+0

Eso es interesante sobre el rsplit. Supongo que nunca lo encontré. – Adam

+0

Una prueba rápida de los dos enfoques (Python 2.4.3): Código de Adam: >>> smart_truncate ('El rápido zorro marrón saltó sobre el perro perezoso.', 26) "El zorro marrón rápido saltó ... " Con el código de bobince: >>> smart_truncate ('El zorro marrón rápido saltó sobre el perro perezoso.', 26) El zorro café rápido ... –

+0

Sí, he añadido de longitud + 1 en el truncamiento para manejar si el truncamiento se divide exactamente al final de una palabra de forma natural. – Adam

3
def smart_truncate(s, width): 
    if s[width].isspace(): 
     return s[0:width]; 
    else: 
     return s[0:width].rsplit(None, 1)[0] 

probándola:

>>> smart_truncate('The quick brown fox jumped over the lazy dog.', 23) + "..." 
'The quick brown fox...' 
+0

Nota: Si ancho> len (s), obtiene un fuera de límites en s [ancho]. Es probable que desee un cheque adicional para el caso en que no sea necesario el truncamiento. – Brian

7
def smart_truncate1(text, max_length=100, suffix='...'): 
    """Returns a string of at most `max_length` characters, cutting 
    only at word-boundaries. If the string was truncated, `suffix` 
    will be appended. 
    """ 

    if len(text) > max_length: 
     pattern = r'^(.{0,%d}\S)\s.*' % (max_length-len(suffix)-1) 
     return re.sub(pattern, r'\1' + suffix, text) 
    else: 
     return text 

O

def smart_truncate2(text, min_length=100, suffix='...'): 
    """If the `text` is more than `min_length` characters long, 
    it will be cut at the next word-boundary and `suffix`will 
    be appended. 
    """ 

    pattern = r'^(.{%d,}?\S)\s.*' % (min_length-1) 
    return re.sub(pattern, r'\1' + suffix, text) 

O

def smart_truncate3(text, length=100, suffix='...'): 
    """Truncates `text`, on a word boundary, as close to 
    the target length it can come. 
    """ 

    slen = len(suffix) 
    pattern = r'^(.{0,%d}\S)\s+\S+' % (length-slen-1) 
    if len(text) > length: 
     match = re.match(pattern, text) 
     if match: 
      length0 = match.end(0) 
      length1 = match.end(1) 
      if abs(length0+slen-length) < abs(length1+slen-length): 
       return match.group(0) + suffix 
      else: 
       return match.group(1) + suffix 
    return text 
+0

siempre me encantan las soluciones basadas en expresiones regulares :) –

+0

esto (al menos la mejor solución) funciona incluso para cadenas sin espacios (luego corta el límite de palabras), aunque en ese caso no agrega el sufijo :) –

11

Hay algunas sutilezas que pueden o no haber problemas para que, como el manejo de fichas (Ej. si los está mostrando como 8 espacios, pero tratándolos como 1 carácter internamente), manejando varios sabores de espacios en blanco de ruptura y sin interrupción, o permitiendo romper la separación silábica, etc. Si algo de esto es deseable, es posible que desee tomar una mira el módulo de envoltura de texto. por ejemplo:

def truncate(text, max_size): 
    if len(text) <= max_size: 
     return text 
    return textwrap.wrap(text, max_size-3)[0] + "..." 

El comportamiento predeterminado de palabras mayores que max_size es para romperlas (haciendo max_size un límite duro). Puede cambiar al límite suave utilizado por algunas de las otras soluciones pasando aquí break_long_words = False to wrap(), en cuyo caso devolverá la palabra completa. Si desea cambiar este comportamiento a la última línea:

lines = textwrap.wrap(text, max_size-3, break_long_words=False) 
    return lines[0] + ("..." if len(lines)>1 else "") 

Hay algunas otras opciones como expand_tabs que pueden ser de interés en función del comportamiento exacto que desea.

6
>>> import textwrap 
>>> textwrap.wrap('The quick brown fox jumps over the lazy dog', 12) 
['The quick', 'brown fox', 'jumps over', 'the lazy dog'] 

Usted acaba de tomar el primer elemento de esa y ya está ...

+3

'textwrap. acortar ("Hola mundo", ancho = 10, marcador de posición = "...") 'produciría' "Hola ..." ' https://docs.python.org/3.5/library/textwrap.html – Salami

+0

I Acabo de probar este y se rompió en medio de un clúster de grafemas, por lo que ni siquiera se está rompiendo el carácter adecuado, y mucho menos se rompe la palabra. – Trejkaz

0

De Python 3.4+ puede utilizar textwrap.shorten. Con el ejemplo OP:

>>> import textwrap 
>>> original = "This is really awesome." 
>>> textwrap.shorten(original, width=20, placeholder="...") 
'This is really...' 

TextWrap.acortar (texto, ancho, ** kwargs)

Contraer y truncar el texto dado para que quepa en el ancho dado.

Primero, el espacio en blanco del texto se contrae (todos los espacios en blanco se reemplazan por espacios simples). Si el resultado se ajusta al ancho, se devuelve . De lo contrario, suficientes palabras son lanzadas desde el final para que los palabras restantes, más el ajuste marcador de posición dentro de la anchura:

Cuestiones relacionadas