45 votes

Tronquer une chaîne sans se terminer au milieu d'un mot

Je cherche un moyen de tronquer une chaîne en Python qui ne coupera pas la chaîne au milieu d'un mot.

Par exemple:

Original: "C'est vraiment génial."
"Dumb" tronque: "C'est réel ..."
"Intelligent" tronqué: "C'est vraiment ..."

Je cherche un moyen d'accomplir le tronçon "intelligent" d'en haut.

69voto

Adam Points 2544

J'ai en fait écrit une solution pour cela sur un de mes projets récents. J'ai compressé la majorité de celui-ci pour être un peu plus petit.

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

Ce qui se passe, c'est que l'instruction if vérifie si votre contenu est déjà inférieur au point de coupure. Si ce n'est pas le cas, il tronque à la longueur souhaitée, se divise sur l'espace, supprime le dernier élément (pour que vous ne coupiez pas un mot), puis le rassemble à nouveau (tout en collant sur le '...') .

48voto

bobince Points 270740

Voici une version légèrement meilleure de la dernière ligne de la solution d'Adam:

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

(Ceci est légèrement plus efficace et renvoie un résultat plus sensible dans le cas où il n'y a pas d'espaces à l'avant de la chaîne.)

11voto

Brian Points 48423

Il y a quelques subtilités qui peuvent ou peuvent ne pas être les problèmes pour vous, comme la gestion des onglets (par exemple. si vous êtes en les présentant comme des 8 espaces, mais de les traiter comme 1 caractère interne), le traitement des différentes saveurs de la rupture et de non-rupture des espaces, ou de permettre à la rupture sur la coupure de mots, etc. Si tout cela est souhaitable, vous voudrez peut-être prendre un coup d'oeil au module d'habillage de texte. par exemple:

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

Le comportement par défaut pour les mots de plus de max_size est pour les casser (prise de max_size une dure limite). Vous pouvez modifier la limite douce utilisée par les autres solutions ici en passant break_long_words=False pour wrap(), auquel cas il sera de retour le mot en entier. Si vous voulez que ce changement de comportement de la dernière ligne:

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

Il ya quelques autres options comme expand_tabs qui peuvent être d'intérêt selon la nature exacte de comportement que vous voulez.

9voto

Markus Jarderot Points 33893
 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
 

OU

 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)
 

OU

 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
 

3voto

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

Le tester:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X