2009-08-18 167 views
10

我不知道是否有插件來啓用某種智能截斷。我需要用一個詞或一個句子的精確度來截斷我的文本。Rails:智能文本截斷

例如:

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. 

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 ... 

回答

20

我還沒有見過這樣的插件,但有一個similar question,可以作爲一個lib或輔助功能的基礎。

你顯示函數的方式似乎把它作爲字符串的擴展:除非你真的想在視圖外執行此操作,否則我傾向於在application_helper.rb中使用函數。也許這樣的事情?

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

哦,那是一個很好的答案!非常感謝! 現在我看到一個真正的理由來增加我在正則表達式中的知識。 – gmile 2009-08-18 15:59:38

+0

它不能像預期的那樣使用句子。它增加了句子之間的分隔符(點)。 – ciembor 2013-04-23 12:22:11

+0

這樣做:'return s.split(/ \。(\ s | $)+ /)。reject {| s | s.strip.empty? } [0,opts [:sentences]]。map {| s | s.strip} .join('。')+'...'' – ciembor 2013-04-23 12:30:37

8

這將基於指定的char_limit長度截斷字邊界。所以它不會在奇怪的地方截斷句子

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

這不包括字符數中的空格。如果你想佔空間,它應該有大小+ = token.size + 1。 – 2012-02-14 05:02:59

+0

您應該編輯您的答案以在問號之前包含空格,因爲if語句的語法短語在語法上是錯誤的。 – 2013-05-22 07:50:12

+0

我編輯了上面的代碼來反映評論中提到的錯誤。它似乎在我的系統上正常工作 – djsumdog 2015-11-10 09:44:33

0

好幫手。因爲我有不同的經歷,所以我改變了它,讓它停止了最後一個字,並處理字符限制。我認爲這在大多數應用中都是更真實的場景。

更新:取了上面的代碼並更新了一下。對於老紅寶石來說,它看起來好得多,並且可以與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

實際上看着soulofpeace代碼它確實允許使用utf8和mb_chars。所以我拿了他的代碼並改進了一下。 – 2012-09-19 09:41:11

0

現在的工作相當長一段時間對不同項目的一些更新,我想出了代碼的這些改進,似乎在現實生活中的場景更有用。

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

如果你想剝離任何可能與該文本一起傳遞的標籤,你也可以執行'ActionController :: Base.helpers.strip_tags(text)',如果你願意的話。 – 2013-05-22 07:58:58

1

該創業板truncate_html完成這項工作。它也可以跳過HTML片斷 - 這可能很有用 - 並提供了自定義字邊界正則表達式的可能性。此外,所有參數的默認值可以在您的config/environment.rb中配置。

例子:

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>