2009-08-18 44 views
10

Tôi tự hỏi nếu có một plugin để cho phép một loại cắt ngắn thông minh. Tôi cần cắt ngắn văn bản của mình với độ chính xác của một từ hoặc một câu.Rails: Cắt ngắn văn bản thông minh

Ví dụ:

Post.my_message.smart_truncate(
    "Once upon a time in a world far far away. And they found that many people 
    were sleeping better.", :sentences => 1) 
# => Once upon a time in a world far far away. 

hoặc

Post.my_message.smart_truncate(
    "Once upon a time in a world far far away. And they found that many people 
    were sleeping better.", :words => 12) 
# => Once upon a time in a world far far away. And they ... 

Trả lời

20

Tôi chưa thấy một plugin như vậy, nhưng có một similar question mà có thể đóng vai trò là cơ sở cho một lib hoặc helper chức năng.

Cách bạn hiển thị hàm dường như đặt nó làm tiện ích mở rộng cho Chuỗi: trừ khi bạn thực sự muốn có thể thực hiện việc này bên ngoài chế độ xem, tôi muốn nghiêng về chức năng trong application_helper.rb. Một cái gì đó như thế này, có lẽ?

module ApplicationHelper 

    def smart_truncate(s, opts = {}) 
    opts = {:words => 12}.merge(opts) 
    if opts[:sentences] 
     return s.split(/\.(\s|$)+/)[0, opts[:sentences]].map{|s| s.strip}.join('. ') + '.' 
    end 
    a = s.split(/\s/) # or /[ ]+/ to only split on spaces 
    n = opts[:words] 
    a[0...n].join(' ') + (a.size > n ? '...' : '') 
    end 
end 

smart_truncate("a b c. d e f. g h i.", :sentences => 2) #=> "a b c. d e f." 
smart_truncate("apple blueberry cherry plum", :words => 3) #=> "apple blueberry cherry..." 
+0

Oh, đó là một câu trả lời thực sự tốt! Cảm ơn rất nhiều! Bây giờ tôi thấy một lý do thực sự để tăng kiến ​​thức của tôi trong các biểu thức chính quy. – gmile

+0

Nó không hoạt động như mong đợi với câu. Nó thêm vào nhiều dấu phân cách (dấu chấm) giữa các câu. – ciembor

+0

Tác phẩm này: 'return s.split (/ \. (\ S | $) + /). Từ chối {| s | s.strip.empty? } [0, opts [: câu]]. Bản đồ {| s | s.strip} .join ('.') + '...' ' – ciembor

8

Điều này sẽ cắt ngắn tại ranh giới từ dựa trên độ dài char_limit được chỉ định. Vì vậy, nó sẽ không cắt ngắn câu tại những nơi kỳ lạ

def smart_truncate(text, char_limit) 
    size = 0 
    text.split().reject do |token| 
     size += token.size() + 1 
     size > char_limit 
    end.join(' ') + (text.size() > char_limit ? ' ' + '...' : '') 
end 
+2

Điều này không bao gồm các khoảng trống trong số ký tự. Nó sẽ có kích thước + = token.size + 1 nếu bạn muốn chiếm không gian. –

+0

Bạn nên chỉnh sửa câu trả lời của mình để bao gồm dấu cách trước dấu chấm hỏi dưới dạng cú pháp ngắn cho câu lệnh if else sai cú pháp. –

+0

Tôi đã chỉnh sửa mã trên để phản ánh các lỗi được đề cập trong các nhận xét. Dường như nó hoạt động chính xác trên hệ thống của tôi – djsumdog

0

Trợ giúp tốt. Vì tôi có một trải nghiệm khác, tôi đã thay đổi nó để nó dừng lại ở từ cuối cùng và làm việc với giới hạn ký tự. Tôi nghĩ đây là kịch bản thế giới thực hơn trong hầu hết các ứng dụng.

Cập nhật: Đã lấy mã ở trên và cập nhật một chút. Dường như phương pháp tiếp cận đẹp hơn cho ruby ​​cũ và làm việc với utf8.

def smart_truncate(text, char_limit) 
    text = text.squish 
    size = 0 
    text.mb_chars.split().reject do |token| 
    size+=token.size() 
    size>char_limit 
    end.join(" ") 
end 
+0

Thực ra nhìn vào mã soulofpeace nó cho phép làm việc với utf8 và mb_chars. Vì vậy, tôi lấy mã của mình và cải thiện một chút. –

0

Làm việc trong một thời gian ngắn trên một số cập nhật với các dự án khác nhau và tôi đã đưa ra các cải tiến mã này có vẻ hữu dụng hơn trong các tình huống thực tế.

def smart_truncate_characters(text, char_limit) 
    text = text.to_s 
    text = text.squish 
    size = 0 
    new_text = text.mb_chars.split().reject do |token| 
    size+=token.size() 
    size>char_limit 
    end.join(" ") 
    if size > char_limit 
    return new_text += '…' 
    else 
    return new_text 
    end 
end 

def smart_truncate_sentences(text, sentence_limit) 
    text = text.to_s 
    text = text.squish 
    size = 0 
    arr = text.mb_chars.split(/(?:\.|\?|\!)(?= [^a-z]|$)/) 
    arr = arr[0...sentence_limit] 
    new_text = arr.join(".") 
    new_text += '.' 
end 

def smart_truncate(text, sentence_limit, char_limit) 
    text = smart_truncate_sentences(text, sentence_limit) 
    text = smart_truncate_characters(text, char_limit) 
end 
+0

Bạn cũng có thể thực hiện 'ActionController :: Base.helpers.strip_tags (văn bản)' nếu bạn muốn loại bỏ bất kỳ thẻ nào có thể được chuyển cùng với văn bản đó nếu bạn thích. –

1

Đá quý truncate_html thực hiện công việc này. Nó cũng có thể bỏ qua các mẩu HTML - có thể yên tĩnh hữu ích - và cung cấp khả năng tùy chỉnh regex biên từ. Hơn nữa, mặc định cho tất cả các tham số có thể được cấu hình ví dụ như trong config/environment.rb của bạn.

Ví dụ:

some_html = '<ul><li><a href="http://whatever">This is a link</a></li></ul>' 

truncate_html(some_html, :length => 15, :omission => '...(continued)') 
=> <ul><li><a href="http://whatever">This...(continued)</a></li></ul> 
Các vấn đề liên quan