query - ruby rails active record
Ruby: substring a una cierta longitud y también al último espacio en blanco dentro de la subcadena (6)
Estoy tratando de truncar una larga cadena de texto a una cierta longitud, pero también quiero asegurarme de que el resultado truncado finalice en un espacio en blanco. También voy a agregar una elipsis después.
Por ejemplo esto:
"This is a very long string that has more characters than I want in it."
se convierte en esto:
"This is a very long string that..."
Estoy empezando con esto, pero obviamente esto no trata el problema de terminar la cadena en espacios en blanco.
<%= item.description[0..30] %>…
La respuesta de @ evfwcqcg es muy buena. Encontré que no funcionó bien cuando
- La cadena contenía otros caracteres que no son espaciales y que no son alfanuméricos.
- La cuerda es más corta que la longitud deseada.
Demostración:
>> s = "How about we put some ruby method Class#Method in our string"
=> "How about we put some ruby method Class#Method in our string"
>> s[0..41].gsub(//s/w+/s*$/, ''...'')
=> "How about we put some ruby method Class#Me"
>> s[0..999].gsub(//s/w+/s*$/, ''...'')
=> "How about we put some ruby method Class#Method in our..."
Esto no es lo que esperaba.
Esto es lo que estoy usando para arreglar esto:
def truncate s, length = 30, ellipsis = ''...''
if s.length > length
s.to_s[0..length].gsub(/[^/w]/w+/s*$/, ellipsis)
else
s
end
end
Al hacer pruebas, aquí está el resultado:
>> s = "This is some text it is really long"
=> "This is some text it is really long"
>> truncate s
=> "This is some text it is..."
Todavía se comporta como se esperaba.
>> s = "How about we put some ruby method Class#Method in our string"
=> "How about we put some ruby method Class#Method in our string"
>> truncate s, 41
=> "How about we put some ruby method Class..."
>> truncate s, 999
=> "How about we put some ruby method Class#Method in our string"
Esto es más como eso.
Me sorprende que ninguna de las respuestas sea realmente correcta (o que esté limitada por el uso de rails helper) aunque esta es una pregunta muy antigua, así que aquí está la solución.
Permite formular claramente cuál es el objetivo primero. Queremos truncar cadenas de 30 caracteres y cortar la última palabra también si no puede encajar del todo. También queremos truncar espacios al final del resultado y agregar puntos suspensivos, si el texto fue acortado.
Si el texto es más largo que el límite, entonces el acortamiento es tan fácil como
s[0,s.rindex(//s/,30)].rstrip + ''...''
Si quisiéramos que el resultado completo tuviera un máximo de 30 caracteres, entonces es tan simple como restar la longitud de la elipse de 30. Entonces, debido a que usamos tres puntos (y no un carácter de tres puntos) de los que necesitamos
s[0,s.rindex(//s/,27)].rstrip + ''...''
Y el resultado final (con la prueba de si tenemos que truncar en absoluto) es:
if s.length<=30
s
else
s[0,s.rindex(//s/,27)].rstrip + ''...''
end
Eso es.
Nota: Hay algunos casos turbios, cuando el resultado deseado no es obvio. Aquí están:
- Si la cadena termina con muchos espacios (
s= "Helo word "
) pero es más corta que 30. ¿Se deben preservar los espacios? - Actualmente lo son. - Lo mismo que arriba, pero los espacios al final cruzan el límite de 30. Al igual que en (
s= "Twentyseven chars long text "
): actualmente, todos los espacios hasta el final se truncan y se añaden puntos suspensivos.
Si usa Rails 4+, debe usar el método truncate
ayuda integrada, por ejemplo:
<%= truncate item.description, length: 30, separator: //w+/ %>
La cadena "..." se agregará al texto truncado; para especificar una cadena diferente, use la opción :omission
, por ejemplo, omission: "xxx"
.
Para Rails 3.x, la opción :separator
debe ser una cadena. Dar :separator => " "
estará bien en muchos casos, pero solo atrapa espacios y no otros espacios en blanco. Un compromiso sería usar String#squish
, que reemplaza todas las secuencias de espacios en blanco con un solo espacio (y también recorta el espacio en blanco "foo/n/tbar ".squish
y final), por ejemplo, "foo/n/tbar ".squish
produce "foo bar"
. Se vería así:
<%= truncate item.description.squish, :length => 30, :separator => //w/,
:omission => "…" %>
class String
def trunca(length=100, ellipsis=''...'')
self.length > length ? self[0..length].gsub(//s*/S*/z/, '''').rstrip+ellipsis : self.rstrip
end
end
Ejemplo:
-bash> irb
2.0.0p247 :001 > class String
2.0.0p247 :002?> def trunca(length=100, ellipsis=''...'')
2.0.0p247 :003?> self.length > length ? self[0..length].gsub(//s*/S*/z/, '''').rstrip+ellipsis : self.rstrip
2.0.0p247 :004?> end
2.0.0p247 :005?> end
=> nil
2.0.0p247 :006 > s = "This is a very long string that has more characters than I want to display."
=> "This is a very long string that has more characters than I want to display."
2.0.0p247 :007 > s.trunca(20)
=> "This is a very long..."
2.0.0p247 :008 > s.trunca(31)
=> "This is a very long string that..."
desc.gsub(/([/w/s]{30}).+/,''/1...'')
Ampliando la respuesta por @evfwcqcg, esta es una expresión pura que resuelve el problema del espacio en blanco al final.
irb(main):031:0> desc="This is some text it is really long"
irb(main):033:0> desc.gsub(/([/w/s]{30}).+/,''/1...'')
=> "This is some text it is really..."
irb(main):034:0> desc="This is some text it is really"
=> "This is some text it is really"
irb(main):035:0> desc.gsub(/([/w/s]{30}).+/,''/1...'')
=> "This is some text it is really"
irb(main):036:0> desc="This is some text it is real"
=> "This is some text it is real"
irb(main):037:0> desc.gsub(/([/w/s]{30}).+/,''/1...'')
=> "This is some text it is real"
s[0..30].gsub(//s/w+/s*$/, ''...'')
La respuesta original no funcionó en el caso en que la subcadena de 30 caracteres terminó en un carácter de espacio en blanco. Esto resuelve eso.
>> desc="This is some text it is really long"
>> desc[0..30].gsub(//s/w+$/,''...'')
"This is some text it is really "
>> desc[0..30].gsub(//s/w+/s*$/,''...'')
"This is some text it is..."