2008-10-30 14 views
37

Szukam sposobu obcięcia łańcucha w języku Python, który nie będzie odcinał ciągu w środku słowa.Ucinaj ciąg bez kończenia w środku słowa

Na przykład:

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

Szukam sposobu, aby osiągnąć „inteligentne” obciąć z góry.

Odpowiedz

56

Właściwie to napisałem rozwiązanie tego w ostatnim projekcie. Sprężynąłem większość, by być trochę mniejszym.

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

Co się dzieje, IF-oświadczenie sprawdza, czy treść jest już mniej niż punkt odcięcia. Jeśli tak nie jest, obcina się do żądanej długości, dzieli się na przestrzeń, usuwa ostatni element (tak, aby nie odciąć słowa), a następnie łączy go z powrotem (podczas sczepiania na "...") .

+0

Jest to bardzo zwięzły ... Chciałbym dodać jeszcze jeden test, aby uniknąć pustych strun w przypadku braku spacje w ogóle w pierwszych znakach "długości". – Jonas

+5

Obcinanie musi uwzględniać długość sufiksu: 'return '' .join (content [: length + 1-len (suffix)]. Split ('') [0: -1]) + sufiks' – Stan

43

Oto nieco lepsza wersja ostatniej linii w roztworze Adama:

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

(ta jest nieco bardziej wydajny i zwraca bardziej rozsądny wynik w przypadku braku miejsca w przedniej części łańcucha .)

+0

To interesujące rsplit. Chyba nigdy tego nie spotkałem. – Adam

+0

Szybki test dwóch podejść (Python 2.4.3): Kod Adama: >>> smart_truncate ("Szybki brązowy lis przeskoczył nad leniwym psem.", 26) "Szybki brązowy lis skoczył ... " z kodu bobince za >>> smart_truncate (« szybki brązowy lis przeskoczył nad leniwym psem», 26) szybki brązowy lis ... –

+0

Tak, dodałem długości + 1 na obcięcie obsłużyć jeśli obcięcie dzieli się dokładnie na końcu słowa w sposób naturalny. – Adam

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

Testowanie to:

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

Uwaga: Jeśli szerokość> len (y), otrzymasz wartość poza zakresem s [szerokość]. Prawdopodobnie potrzebujesz dodatkowej kontroli w przypadku, gdy obcięcie nie jest potrzebne. – 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 

LUB

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) 

LUB

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

Zawsze uwielbiam rozwiązania oparte na regex :) –

+0

to (przynajmniej najlepsze rozwiązanie) działa nawet dla ciągów bez spacji (wtedy przecina granicę słowa), chociaż w tym przypadku nie dodaje sufiksu :) –

11

Istnieje kilka subtelności, które mogą lub nie mogą być problemy dla Ciebie, takie jak obsługa zakładek (np. jeśli wyświetlasz je jako 8 spacji, ale traktujesz je jako 1 znak wewnętrznie), obsługując różne smaki łamania i nienaruszania białych znaków lub zezwalając na dzielenie wyrazów itp. Jeśli któreś z nich jest pożądane, możesz wziąć spójrz na moduł textwrap. np:

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

Domyślne zachowanie słów większych niż MAX_SIZE jest je złamać (making MAX_SIZE twarde limitu). Możesz przejść do miękkiego limitu używanego przez niektóre inne rozwiązania, przekazując break_long_words = False to wrap(), w takim przypadku zwróci ono całe słowo. Jeśli chcesz to zachowanie zmienić ostatni wiersz:

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

Istnieje kilka innych opcji, takich jak expand_tabs, które mogą być interesujące w zależności od dokładnego zachowania chcesz.

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

Wystarczy wziąć pierwszy element, który i gotowe ...

+3

'textwrap. shorten ("Hello world", width = 10, placeholder = "...") 'spowoduje utworzenie' "Hello ..." ' https://docs.python.org/3.5/library/textwrap.html – Salami

+0

I właśnie wypróbowałem to i złamało się w środku grupy grafemów, więc nie robi nawet właściwego łamania charakteru, nie mówiąc już o łamaniu słów. – Trejkaz

0

Od Python 3.4+ można używać textwrap.shorten. Na przykładzie PO:

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

odpychania tekstu.Skróć (tekst, szerokość, ** kwargs)

Zwiń i obcina podany tekst, aby dopasować go do podanej szerokości.

Najpierw białe znaki w tekście są zwinięte (wszystkie białe znaki są zastępowane pojedynczymi odstępami). Jeśli wynik pasuje do szerokości, zwracana jest wartość . W przeciwnym razie, dość słów, są odrzucane od końca tak, że pozostałe słowa plus dopasowanie zastępczy w szerokości:

Powiązane problemy