2008-10-30 47 views

Trả lời

56

Tôi thực sự đã viết giải pháp cho dự án gần đây của tôi. Tôi đã nén phần lớn nó xuống nhỏ hơn một chút.

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

Điều gì sẽ xảy ra nếu kiểm tra câu lệnh nếu nội dung của bạn đã nhỏ hơn điểm cắt. Nếu không, nó cắt ngắn đến độ dài mong muốn, chia nhỏ trên không gian, loại bỏ phần tử cuối cùng (để bạn không cắt một từ), và sau đó kết hợp lại với nhau (trong khi tacking '...') .

+0

Điều này thực sự ngắn gọn ... Tôi muốn thêm một thử nghiệm nữa để tránh các chuỗi rỗng trong trường hợp không có không gian ở tất cả các ký tự "độ dài" đầu tiên. – Jonas

+5

Việc cắt ngắn phải xem xét độ dài hậu tố: 'return '' .join (nội dung [: length + 1-len (hậu tố)]. Split ('') [0: -1]) + hậu tố ' – Stan

43

Dưới đây là một phiên bản tốt hơn một chút trong những dòng cuối cùng trong A-đam của giải pháp:

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

(Đây là một chút hiệu quả hơn, và trả về một kết quả hợp lý hơn trong trường hợp không có dấu cách ở phía trước của chuỗi .)

+0

Điều thú vị về rsplit. Tôi đoán tôi không bao giờ chạy qua nó. – Adam

+0

Một thử nghiệm nhanh về hai cách tiếp cận (Python 2.4.3): Mã của Adam: >>> smart_truncate ('Con cáo nâu nhanh chóng nhảy qua con chó lười.', 26) "Con cáo màu nâu nhanh chóng nhảy ... " Với mã của bobince: >>> smart_truncate ('Con cáo màu nâu nhanh chóng nhảy qua con chó lười.', 26) Con cáo màu nâu nhanh ... –

+0

Vâng, tôi đã thêm chiều dài + 1 vào phần cắt ngắn để xử lý nếu cắt ngắn tách chính xác ở cuối một từ một cách tự nhiên. – Adam

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

kiểm tra nó:

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

Lưu ý: Nếu chiều rộng> len (s), bạn nhận được một trong giới hạn trên s [chiều rộng]. Bạn có thể muốn kiểm tra thêm cho trường hợp không cần cắt bớt. – 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 

HOẶC

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) 

HOẶC

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

Tôi luôn luôn yêu thích giải pháp dựa trên regex :) –

+0

(ít nhất là giải pháp hàng đầu) hoạt động ngay cả đối với chuỗi không có dấu cách (sau đó cắt đường biên), mặc dù trong trường hợp đó không thêm hậu tố :) –

11

Có một vài sự tinh tế có thể có hoặc không thể có vấn đề cho bạn, chẳng hạn như xử lý các tab (Ví dụ. nếu bạn hiển thị chúng dưới dạng 8 dấu cách, nhưng xử lý chúng dưới dạng 1 ký tự bên trong), xử lý các hương vị khác nhau của khoảng trắng phá vỡ và không phá vỡ, hoặc cho phép phá vỡ dấu gạch ngang, v.v. nhìn vào mô-đun textwrap. ví dụ:

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

Hành vi mặc định cho các từ lớn hơn max_size là phá vỡ chúng (làm tối đa hóa giới hạn cứng). Bạn có thể thay đổi thành giới hạn mềm được sử dụng bởi một số giải pháp khác ở đây bằng cách chuyển break_long_words = False thành wrap(), trong trường hợp này nó sẽ trả về toàn bộ từ. Nếu bạn muốn hành vi này thay đổi dòng cuối cùng thành:

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

Có một số tùy chọn khác như expand_tabs có thể quan tâm tùy thuộc vào hành vi chính xác mà bạn muốn.

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

Bạn chỉ lấy phần tử đầu tiên đó và bạn đã hoàn tất ...

+3

'textwrap. rút gọn ("Hello world", width = 10, placeholder = "...") 'sẽ tạo ra' "Xin chào ..." ' https://docs.python.org/3.5/library/textwrap.html – Salami

+0

I chỉ cần cố gắng này và nó đã phá vỡ ở giữa một cụm grapheme, do đó, nó thậm chí không làm việc phá vỡ nhân vật thích hợp, hãy để một mình từ phá vỡ. – Trejkaz

0

Từ Python 3.4 trở lên, bạn có thể sử dụng textwrap.shorten. Với ví dụ OP:

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

textwrap.rút ngắn (văn bản, chiều rộng, ** kwargs)

Thu gọn và cắt bớt văn bản đã cho vừa với chiều rộng đã cho.

Đầu tiên khoảng trắng trong văn bản bị thu gọn (tất cả khoảng trắng được thay thế bằng dấu cách đơn). Nếu kết quả phù hợp với chiều rộng, nó được trả về là . Nếu không, đủ từ được bỏ từ cuối để các từ còn lại cộng với trình giữ chỗ vừa với chiều rộng:

Các vấn đề liên quan