2009-08-18 10 views
10

Me pregunto si hay un complemento que permita un tipo de truncamiento inteligente. Necesito truncar mi texto con una precisión de una palabra o de una oración.Rieles: truncado de texto inteligente

Por ejemplo:

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. 

o

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

Respuesta

20

No he visto un plugin de este tipo, pero había una similar question que podría servir como base para una función lib o ayudante.

La forma en que muestra la función parece ponerla como una extensión de String: a menos que realmente desee poder hacer esto fuera de una vista, me inclinaría por una función en application_helper.rb. Algo como esto, tal vez?

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, eso fue una muy buena respuesta! ¡Muchas gracias! Ahora veo una razón real para aumentar mi conocimiento en expresiones regulares. – gmile

+0

No funciona como se esperaba con oraciones. Agrega muchos separadores (puntos) entre oraciones. – ciembor

+0

Esto funciona: 'return s.split (/ \. (\ S | $) + /). Rechaza {| s | s.strip.empty? } [0, opts [: oraciones]]. Map {| s | s.strip} .join ('.') + '...' ' – ciembor

8

Esto truncadas en el límite de palabra basado en la longitud char_limit especificado. Por lo tanto, no truncará la oración en lugares extraños

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

Esto no incluye espacios actuales en el recuento de caracteres. Debería tener el tamaño + = token.size + 1 si desea contabilizar espacios. –

+0

Debe editar su respuesta para incluir espacio antes del signo de interrogación como la sintaxis corta para la declaración else else es sintácticamente incorrecta. –

+0

He editado el código anterior para reflejar los errores mencionados en los comentarios. Parece que está funcionando correctamente en mi sistema – djsumdog

0

Nice helper. Como tuve una experiencia diferente, la cambié para que se detuviera en la última palabra y funcionara con límite de caracteres. Creo que este es un escenario mucho más real en la mayoría de las aplicaciones.

Actualización: Tomó el código anterior y lo actualizó un poco. Parecía un enfoque mucho más agradable para el viejo rubí y funciona con 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

En realidad, al mirar el código de soulofpeace, permite trabajar con utf8 y mb_chars. Así que tomé su código y mejoré un poco. –

0

de trabajo durante bastante tiempo ahora en algunas actualizaciones con diferentes proyectos y se me ocurrió con estos refinamientos del código que parecen mucho más útil en escenarios de la vida real.

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

También puede hacer 'ActionController :: Base.helpers.strip_tags (text)' si desea quitar cualquier etiqueta que pueda pasar junto con ese texto si así lo prefiere. –

1

La gema truncate_html hace este trabajo. También puede omitir fragmentos de HTML, que pueden ser muy útiles, y ofrece la posibilidad de personalizar la expresión de límite de palabras de la palabra. Además, los valores predeterminados para todos los parámetros se pueden configurar, por ejemplo, en su config/environment.rb.

Ejemplo:

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> 
Cuestiones relacionadas