1 2 3 4 5 6 7
@wordsToHighlight=["important","monkey","dancing"] def highlightText(input) for i in 0..@wordsToHighlight.length-1 do input = input.gsub(@wordsToHighlight[i],"*" + @wordsToHighlight[i] + "*") end return input end
Refactorings
No refactoring yet !
macournoyer
January 3, 2008, January 03, 2008 14:26, permalink
Here's my take, it's short but not perfect
1 2 3 4 5 6
def highlight_text(input, words_to_highlight=%w(important monkey dancing)) input.gsub(/#{words_to_highlight.join('|')}/i, '*\0*') end puts highlight_text("Hey monkey, it's important you start dancing right now!") # >> Hey *monkey*, it's *important* you start *dancing* right now!
mvanholstyn
January 3, 2008, January 03, 2008 14:33, permalink
1 2 3
def highlight_text(input, words_to_highlight = [], wrapper = '*\1*') input.gsub(/\b(#{words_to_highlight.join("|")})\b/, wrapper) end
Jason
January 3, 2008, January 03, 2008 14:34, permalink
this dumbass ajax form is not working!
1 2 3 4 5 6
def highlightText(input, open_tag, close_tag) input.split(/ /).collect {|word| @wordsToHighlight.include?(word) ? "#{open_tag}#{word}#{close_tag}" : word }.join(" ") end input = "The world of very important things contained many monkeys that really liked dancing around!" p highlightText(input, "<b>", "</b>")
Jason
January 3, 2008, January 03, 2008 14:38, permalink
Revision 2, this time passing in list of words to highlight as a function argument like macournoyer did (first reply), which is much better than accessing a named variable outside of the function.
1 2 3 4 5 6 7
def highlightText(input, open_tag, close_tag, words_to_highlight) input.split(/ /).collect {|word| words_to_highlight.include?(word) ? "#{open_tag}#{word}#{close_tag}" : word }.join(" ") end list_of_words=["important","monkey","dancing"] input = "The world of very important things contained many monkeys that really liked dancing around!" p highlightText(input, "<b>", "</b>", list_of_words)
macournoyer
January 3, 2008, January 03, 2008 14:41, permalink
Sorry about the form not working Jason, should be fixed now
Justin Jones
January 3, 2008, January 03, 2008 15:15, permalink
Good solutions above. This is overkill, but can't think of anything else that hasn't already been done.
1 2 3 4 5 6 7 8 9
class String def hilight(marker = '*', *args) gsub(/\b(#{args.join('|')})\b/, "#{marker}\\1#{marker}") end end words = %w(monkeys dancing important) input = "The world of very important things contained many monkeys that really liked dancing around!" input.hilight('*', *words)
Jason Dew
January 3, 2008, January 03, 2008 17:24, permalink
i purposely wrote this without looking at the refactorings... funny how close it still is but it's a bit different. a little more verbose imo but extensible. the only issue i have with it is that you are limited to one a single delimiter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
class Highlighter def initialize(keywords, prefix='*', suffix='*', delimiter=' ') @keywords, @prefix, @suffix, @delimiter = keywords, prefix, suffix, delimiter end def highlight(text) text.split(@delimiter).collect do |word| @keywords.include?(word) ? highlight_word(word) : word end.join(@delimiter) end private def highlight_word(word) @prefix + word + @suffix end end highlighter = Highlighter.new %w(important monkey dancing) text = "there are some very important monkeys dancing the most important of all dances in monkey land" highlighted_text = highlighter.highlight(text) puts "ORIGINAL : #{text}" puts "HIGHLIGHTED: #{highlighted_text}"
Justin Jones
January 3, 2008, January 03, 2008 20:05, permalink
I'm sure the String#pad (not sure about the name either) utility function added here is available somewhere, but anyways. Also using the block version of gsub this time.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class String def pad(char = ' ') "#{char}#{self}#{char}" end def highlight(marker = '*', *args) gsub(/\b(#{args.join('|')})\b/) { |word| word.pad(marker) } end end words = %w(monkeys dancing important) input = "The world of very important things contained many monkeys that really liked dancing around!" input.highlight('*', *words)
Jens Ruzicka
January 6, 2008, January 06, 2008 14:27, permalink
There are already better versions here
1 2 3 4 5 6 7 8 9 10 11 12 13
def highlight_text words_to_highlight, fore="*", after="*" self.split.each do |token| if words_to_highlight =~ token STDOUT << "#{fore} #{$&} #{after} " else STDOUT << "#{token} " end end end line = "This is an important text about a dancing monkey" line.highlight_text %r{important|dancing|monkey}, "<b>", "</b>" gets
David Madden
January 7, 2008, January 07, 2008 13:51, permalink
Nothing major here, just made it case insensitive. An issue I have is that hyphenated words like "monkey-wrench" will still get highlighted and I have no idea how to get the regexp to ignore words beginning or ending with a -.
1 2 3 4 5 6
def highlight_text(input, words=%w(important monkey dancing), sym='*') input.gsub(/\b(#{words.join("|")})\b/i, "#{sym}\\1#{sym}") end puts highlight_text("This is the Important text to highlight. Can you see the dancing monkey-wrench?")
Mike
January 9, 2008, January 09, 2008 04:55, permalink
Probably went overboard.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
class String def highlight(mark='*') mark+self+mark end end class Sentence attr_writer :words_to_highlight def initialize(string='') @string = string @words_to_highlight = %w() end def highlight(words_to_highlight=@words_to_highlight,mark='*') all_words = @string.split(/\b/) highlighted = all_words.collect do |word| ( words_to_highlight.include?(word) ) ? word.highlight : word end highlighted.join() end def to_s @string end end sentence = Sentence.new("hello world, whats happening?") puts sentence puts sentence.highlight(%w(world whats)) sentence.words_to_highlight = %w(world) puts sentence.highlight
Mike
January 9, 2008, January 09, 2008 05:07, permalink
another one, neither of these work on contractions, this one features recursion and only involves modifying string.
This one outputs:
*hello* world, what's *up*?
1 2 3 4 5 6 7 8 9 10 11
class String def highlight(words=%w(), mark='*') if ( self.split(/\b/).length == 1 ) words.include?(self) ? mark+self+mark : self else self.split(/\b/).collect { |w| w.highlight(words) }.join end end end puts "hello world, what's up?".highlight(%w(hello up))
Mike
January 9, 2008, January 09, 2008 05:11, permalink
found a bug in that one, didnt work when you had a full sentence and passed in a mark.
This one will correctly output +hello+ world, what's +up+?
I'm going to stop now, sorry for the triple post.
1 2 3 4 5 6 7 8 9 10 11
class String def highlight(words=%w(), mark='*') if ( self.split(/\b/).length == 1 ) words.include?(self) ? mark+self+mark : self else self.split(/\b/).collect { |w| w.highlight(words, mark) }.join end end end puts "hello world, what's up?".highlight(%w(hello up), '+')
Simon Gate
January 9, 2008, January 09, 2008 23:43, permalink
How i did it.
1 2 3 4 5 6 7
class String def highlight(words = nil, mark = "*") words.nil? ? self : self.gsub(/#{words.join("|")}/) {|s| "#{mark}#{s}#{mark}"} end end puts "A very important list is in monkey dancing tonight with pants down in rain today.".highlight %w(monkey dancing today)
Sean Cribbs
January 26, 2008, January 26, 2008 18:11, permalink
Regexp.union is your friend! This also demonstrates a typical use of the splat operator to turn an array into an argument list, and the usage of back-references in global substitutions. One thing that I found recently is that your replacement string needs to be in single-quotes or Ruby will turn your \0,\1, etc references into the corresponding ASCII characters instead of the backreferences! If you use a double-quoted string, \\0, \\1 etc. should accomplish the same thing.
1 2 3 4 5 6 7 8
@wordsToHighlight=["important","monkey","dancing"] def highlightText(input) input.gsub(Regexp.union(*@wordsToHighlight), '*\0*') end puts highlightText("I think it's important to have a dancing monkey in your bedroom.") # => I think it's *important* to have a *dancing* *monkey* in your bedroom.
Sean Cribbs
January 26, 2008, January 26, 2008 18:16, permalink
Now having read some of the others, I'll borrow from Simon's idea:
1 2 3 4 5 6 7 8
class String def highlight(words=[]) words.empty? ? self : self.gsub(Regexp.union(*words), '*\0*') end end puts "I think it's important to have a dancing monkey in your bedroom.".highlight %w(important monkey dancing) # => I think it's *important* to have a *dancing* *monkey* in your bedroom.
Here is the 5th edition of Rubyize this. You can find the original blog post on ruby fleebie here : http://www.rubyfleebie.com/rubyize-this-5th-edition/
Tom wrote a very simple ruby script to highlight some words in a text. He chose to highlight the words with asterisks, like *that* (In 2 months, perhaps Tom will have to use his script to produce HTML output or something else... he will be screwed with those basic asterisks). Tom has absolutely no ruby background, help him refactor his code <em>ala</em> Ruby, that is : short, clean and simple.
By the way, Tom didn't put a lot of effort in his algorithm. His dumb gsub thing will mistakenly replace <em>parts of words</em> instead of whole words only. Maybe some improvements would be needed there.