rubyonrails - ¿Cuenta de palabras en Rails?
ruby server (6)
Digamos que tengo un modelo de blog con Título y Cuerpo. ¿Cómo muestro el número de palabras en Cuerpo y caracteres en Título? Quiero que la salida sea algo como esto.
Título: Lorem Cuerpo: Lorem Lorem Lorem
Este post tiene 3 palabras.
Las respuestas aquí tienen un par de cuestiones:
- No tienen en cuenta los caracteres utf y Unicode (diacríticos): áâãêü, etc ...
- No tienen en cuenta los apóstrofes y los guiones. Así que
Joe''s
será considerado como dos palabras deJoe
y lo que obviamente es incorrecto. Al igual quetwenty-two
, que es una sola palabra compuesta.
Algo como esto funciona mejor y explica esos problemas:
foo.scan(/[/p{Alpha}/-'']+/)
Es posible que desee ver mi gema palabras contadas . Permite contar palabras, sus ocurrencias, longitudes y un par de otras cosas. También está muy bien documentado.
counter = WordsCounted::Counter.new(post.body)
counter.word_count #=> 3
counter.most_occuring_words #=> [["lorem", 3]]
# This also takes into capitalisation into account.
# So `Hello` and `hello` are counted as the same word.
Si estás interesado en el rendimiento, escribí un punto de referencia rápido:
require ''benchmark''
require ''bigdecimal/math''
require ''active_support/core_ext/string/filters''
# Where "shakespeare" is the full text of The Complete Works of William Shakespeare...
puts ''Benchmarking shakespeare.scan(//w+/).size x50''
puts Benchmark.measure { 50.times { shakespeare.scan(//w+/).size } }
puts ''Benchmarking shakespeare.squish.scan(//w+/).size x50''
puts Benchmark.measure { 50.times { shakespeare.squish.scan(//w+/).size } }
puts ''Benchmarking shakespeare.split.size x50''
puts Benchmark.measure { 50.times { shakespeare.split.size } }
puts ''Benchmarking shakespeare.squish.split.size x50''
puts Benchmark.measure { 50.times { shakespeare.squish.split.size } }
Los resultados:
Benchmarking shakespeare.scan(//w+/).size x50
13.980000 0.240000 14.220000 ( 14.234612)
Benchmarking shakespeare.squish.scan(//w+/).size x50
40.850000 0.270000 41.120000 ( 41.109643)
Benchmarking shakespeare.split.size x50
5.820000 0.210000 6.030000 ( 6.028998)
Benchmarking shakespeare.squish.split.size x50
31.000000 0.260000 31.260000 ( 31.268706)
En otras palabras, el squish
es lento con cadenas muy grandes ™. Aparte de eso, la split
es más rápida (dos veces más rápida si no usas squish
).
También:
"Lorem Lorem Lorem".split.size
=> 3
"Lorem Lorem Lorem".scan(//S+/).size
=> 3
"Lorem Lorem Lorem".scan(//w+/).size
=> 3
ACTUALIZACIÓN : si necesita hacer coincidir rock-and-roll como una sola palabra, podría hacer lo siguiente
"Lorem Lorem Lorem rock-and-roll".scan(/[/w-]+/).size
=> 4
"caçapão adipisicing elit".scan(/[/w-]+/).size
=> 5
Pero como podemos ver, la oración tiene solo 3 palabras. El problema está relacionado con los caracteres acentuados, porque la expresión regular / w no los considera como un carácter de palabra [A-Za-z0-9_].
Una solución mejorada sería
I18n.transliterate("caçapão adipisicing elit").scan(/[/w-]+/).size
=> 3