2010-01-21 25 views
14

Powiedz, że mam model bloga z tytułem i treścią. Jak pokazuję liczbę słów w Ciała i znaków w tytule? Chcę wyjście być coś takiegoLiczba słów w Railsach?

Tytuł: Lorem ciała: Lorem Lorem Lorem

Ten wpis nie zawiera liczby słów 3.

Odpowiedz

32
"Lorem Lorem Lorem".scan(/\w+/).size 
=> 3 

UPDATE: jeśli trzeba dopasować rock-and-roll jako jedno słowo, można zrobić jak

"Lorem Lorem Lorem rock-and-roll".scan(/[\w-]+/).size 
=> 4 
+0

To dokładnie to, czego szukałem. Dzięki. –

+2

Co powiesz na "dodaj rock-n-roll"? Są tu trzy słowa, podczas gdy twój wariant znajdzie pięć. – IDBD

+0

dodano również łącznik. – YOU

16

też:

"Lorem Lorem Lorem".split.size 
=> 3 
+0

Doświadczyłem tej metody, aby być bardziej wiarygodne,// ​​\ w -] +/regex nie wydaje się bardzo niezawodny. –

+2

Podoba mi się to o wiele więcej. Prosty. Dodałem 'squish' przed' split'. – duma

2
"Lorem Lorem Lorem".scan(/\S+/).size 
=> 3 
4

Jeśli jesteś zainteresowany wydajności, napisałem krótki odniesienia:

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

Efekty:

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) 

Innymi słowy, squish jest powolny z bardzo dużymi Strings ™. Poza tym, split jest szybszy (dwa razy szybszy, jeśli nie używasz squish).

2

Tutejsze odpowiedzi mają kilka problemów:

  1. one nie uwzględniają UTF i Unicode znaków (znaków diakrytycznych): áâãêü itp ...
  2. one nie uwzględniają apostrofami i myślniki . Tak więc Joe's będą uważane za dwa słowa Joe i 's, co jest oczywiście niepoprawne. Podobnie jak twenty-two, który jest pojedynczym złożonym słowem.

Coś jak to działa lepiej i konto dla tych zagadnień:

foo.scan(/[\p{Alpha}\-']+/) 

Możecie zajrzeć do mojego Words Counted gem. Pozwala liczyć słowa, ich wystąpienia, długości i kilka innych rzeczy. Jest również bardzo dobrze udokumentowany.

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. 
1
"caçapão adipisicing elit".scan(/[\w-]+/).size 
=> 5 

Ale jak widać, zdanie ma tylko 3 słów. Problem jest związany z akcentowanymi znakami, ponieważ regex \ w nie uważa ich za znak słowny [A-Za-z0-9_].

udoskonalone rozwiązanie byłoby

I18n.transliterate("caçapão adipisicing elit").scan(/[\w-]+/).size 
=> 3