display the first n words from a string

Hi Max,

In my app, a Story has a summary field, and on the page that lists
stories, i want to show the first 'n' (eg twenty) words from the summary
(which i would follow with "...").

Does anyone know a simple way to do this? I can think of complicated
and ugly ways to do it, involving going through the string a char at a
time counting spaces, but i'm guessing there's a neat rails helper
(since there usually is!).

I usually go for the roll-your-own method, something like this should work nicely for you, just pop the method in your application_helper and call it in your views.

def first_x_words(str,n=20,finish='…')
   str.split(' ')[0,n].inject{|sum,word| sum + ' ' + word} + finish
end

my_string = 'Praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi nam! Modo typi qui nunc nobis videntur parum clari fiant sollemnes?'

p first_x_words(my_string) # => "Praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi nam! Modo typi qui nunc nobis videntur parum clari…"

p first_x_words(my_string, 5, '!!!') # => "Praesent luptatum zzril delenit augue!!!"

Hope this helps.

Douglas F Shearer
dougal.s@gmail.com
http://douglasfshearer.com

… renders correctly across all browsers, even if they don’t respect the utf-8 encoding defined in the header.

Best regards

Peter De Berdt

Peter hit that nail on the head. It also looks a bit neater as the letter-spacing is smaller between the periods of &hellip.

Glad it helped you out.

Douglas F Shearer

dougal.s@gmail.com

http://douglasfshearer.com

First of all, split takes a limiter, and its inverse is join:
words = str.split(' ', n + 1)
words[-1] = finish
words.join(' ')

But is this really what you want? Suppose the book was a discussion
on Mary Poppins? It seems to me that you have space for n characters,
and you need to end at a word break:
letters = str[0..limit - finish.length]
letters.sub!(/ \S*$/)
letters + " " + finish

> def first_x_words(str,n=20,finish='…')
> str.split(' ')[0,n].inject{|sum,word| sum + ' ' + word} + finish
> end

That's perfect, thanks Douglas.
(i would never think to use inject as it still confuses me a little!)

No need for inject--you can rewrite that line:
   str.split(' ')[0,n].join(' ') + finish

If, like another poster said, it is a CHARACTER limitation, yet you
still want to break on a word boundary, then replace the line with:
  str[0,n].sub(/ ?\S*$/,'') + finish

- Mark.

inject here is unnecessarily expensive. I try to avoid using inject if
it isn't really needed.

Using ActionView's truncate() as a model:

def truncate_words(text, num_words = 6, truncate_string = "…")
  if text.nil? then return end
  arr = text.split(' ')
  arr.length > num_words ? arr[0...num_words].join(' ') +
truncate_string : text
end

ReinH
reinh.com

Or how about using an extensible truncation factory:

class Truncator
  def initialize( string, length, ending, truncate_on = "" )
    arr = string.split( truncate_on )
    @truncated_string = arr.length > length ?
arr[0...length].join( truncate_on ).gsub( /\W\Z/, '') + ending :
string
  end

  def to_s
    @truncated_string
  end
end

def truncate(text, length = 30, ending = "…")
  Truncator.new(text, length, ending).to_s
end

def truncate_words(text, length = 8, ending = "…")
  Truncator.new( text, length, ending, truncate_on = " ").to_s
end

def truncate_sentences(text, length = 3, ending = "…")
  Truncator.new( text, length, ending, truncate_on = ".").to_s
end

Usage:

irb(main):033:0> lorem = "Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum."

irb(main):034:0> truncate lorem
=> "Lorem ipsum dolor sit amet, co…"

irb(main):035:0> truncate_words lorem
=> "Lorem ipsum dolor sit amet, consectetur adipisicing elit…"

irb(main):036:0> truncate_sentences lorem
=> "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur…"

ReinH
reinh.com

Check out this helper: http://pastie.textmate.org/94218

Basically the same thing aside from the encapsulation in a class.
Didn't see that one when I wrote mine. I went ahead and pluginized
mine, though, since I'll probaby use it often:

svn://reinh.com/plugins/truncator

truncate, truncate_words, truncate_sentences, truncate_on

Oh, I forgot to mention, it also removes trailing punctuation from the
truncated string to avoid typographical errors like: "Lorem ipsum,..."

Please unsubscribe me from this google group

Thanks

Joseph Chapman,

Joseph:
To unsubscribe from this group, send email to
rubyonrails-talk-unsubscribe@googlegroups.com

Bye!
Mohit.

joseph chapman wrote:

Changing the subject back to something useful.

Max Williams wrote:

Mohit Sindhwani wrote:
  

Joseph:
To unsubscribe from this group, send email to
rubyonrails-talk-unsubscribe@googlegroups.com

Bye!
Mohit.
    
he's a spammer, ignore him :slight_smile:
  
Oops... Didn't realize that, thanks!
But, all the more reason to send him unsubscribe instructions :stuck_out_tongue:

Cheers,
Mohit.
9/7/2007 | 12:08 PM.

Hmm.. why not ban him? Hehe