views:

168

answers:

2

Suppose you want to generate dynamic page titles that look like this:

"It was all a dream, I used to read word up magazine" from "Juicy" by The Notorious B.I.G

I.e., "LYRICS" from "SONG_NAME" by ARTIST

However, your title can only be 69 characters total and this template will sometimes generate titles that are longer.

One strategy for solving this problem is to truncate the entire string to 69 characters. However, a better approach is to truncate the less important parts of the string first. I.e., your algorithm might look something like this:

  1. Truncate the lyrics until the entire string is <= 69 characters
  2. If you still need to truncate, truncate the artist name until the entire string is <= 69 characters
  3. If you still need to truncate, truncate the song name until the entire string is <= 69 characters
  4. If all else fails, truncate the entire string to 69 characters

Ideally the algorithm would also limit the amount each part of the string could be truncated. E.g., step 1 would really be "Truncate the lyrics to a minimum of 10 characters until the entire string is <= 69 characters"

Since this is such a common situation, I was wondering if someone has a library or code snippet that can take care of it.

A: 

I had a similar problem with truncating titles to put them into a tweet. I ended up putting everything in an array and joining it. Code is reasonably readable. Here's a version that's modified to do what you're looking for.

message = [lyrics, " from ", song_name, " by ", artist]
[0, 2, 4].each do |index|
  length = message.join.length
  message[index] = message[index][0...(69-length)]
end
message = message.join

You might also want to append an ellipsis when you truncate, so that people know it's been cut.

zaius
A: 

This is a reasonably full implementation

#!/usr/bin/ruby

MIN_WORD_SIZE = 10
MAX_STRING_SIZE = 55  # 69 - 14 characters for punctuation spacing and conjunctions

def smart_trunc_words(lyrics, artist, title)

  words = [lyrics, artist, title]

  words.each_index do |idx|
    total_length = words.to_s.length
    if ( words[idx].length > MIN_WORD_SIZE and total_length > MAX_STRING_SIZE )
      other_words = total_length - words[idx].length
      max_word_size = [MAX_STRING_SIZE - other_words, MIN_WORD_SIZE].max
      words[idx] = truncate_word words[idx], max_word_size
    end
  end

  words

end

def truncate_word(word, sub_size)
  # Enhance by adding ellipses here or break on a word boundary
  word[0, sub_size]

end

def smart_trunc(lyrics, artist, title)
  lyrics, artist, title  = smart_trunc_words lyrics, artist, title
  '"%s" from "%s" by %s' % [lyrics, title, artist]
end

test_data = [
  [ "It was all a dream, I used to read word up magazine",  "The Notorious B.I.G", "Juicy"],
  [ "Ground Control to Major Tom, your circuits dead there's something wrong",  "David Bowie", "Space Oddity"],
  [ "Back Home they'll be thinking about us", "The England world cup squad (1970)" , "Back Home"],
  [ "I'm the new cancer", "Panic at the disco", "Theres A Good Reason These Tables Are Numbered Honey, You Just Havent Thought Of It Yet"],
  [ "Short lyrics", "short band", "short song"],
  [ "VeryLongLyrics VeryLongLyrics VeryLongLyrics VeryLongLyrics VeryLongLyrics",
    "VeryLongBandName VeryLongBandName VeryLongBandName VeryLongBandName VeryLongBandName",
    "VeryLongTitle VeryLongTitle VeryLongTitle VeryLongTitle VeryLongTitle"]
]


test_data.each do |td|
  lyrics = td[0]
  artist = td[1]
  title = td[2]
  puts 'Original string : "%s" from "%s" by %s' % [lyrics, title, artist]
  puts "New string      : #{smart_trunc lyrics, artist, title}"
end

That produces the following results

Original string : "It was all a dream, I used to read word up magazine" from "Juicy" by The Notorious B.I.G
New string      : "It was all a dream, I used to r" from "Juicy" by The Notorious B.I.G
Original string : "Ground Control to Major Tom, your circuits dead there's something wrong" from "Space Oddity" by David Bowie
New string      : "Ground Control to Major Tom, you" from "Space Oddity" by David Bowie
Original string : "Back Home they'll be thinking about us" from "Back Home" by The England world cup squad (1970)
New string      : "Back Home th" from "Back Home" by The England world cup squad (1970)
Original string : "I'm the new cancer" from "Theres A Good Reason These Tables Are Numbered Honey, You Just Havent Thought Of It Yet" by Panic at the disco
New string      : "I'm the ne" from "Theres A Good Reason These Tables A" by Panic at t
Original string : "Short lyrics" from "short song" by short band
New string      : "Short lyrics" from "short song" by short band
Original string : "VeryLongLyrics VeryLongLyrics VeryLongLyrics VeryLongLyrics VeryLongLyrics" from "VeryLongTitle VeryLongTitle VeryLongTitle VeryLongTitle VeryLongTitle" by VeryLongBandName VeryLongBandName VeryLongBandName VeryLongBandName VeryLongBandName
New string      : "VeryLongLy" from "VeryLongTitle VeryLongTitle VeryLon" by VeryLongBa

No doubt some of the ruby gurus will make it shorter and/or more idiomatic

Steve Weet