2

I am trying to create a method that, given a string, returns three strings: title, description1, description2

This is a related question I found: Split a string into chunks of specified size without breaking words - But my chunks are of different size.

Title needs to be max 25 characters.

Description1 needs to be max 35 characters.

Description2 needs to be max 35 characters.

The question would be:

How can I split a string so that it creates a maximum of three entities (NOTE: If the string can fit in just the first entity that is OK, I don't need to return the three entities), where first entity has a maximum of 25 characters and the other two have a max of 35 characters each. Making the method clever enough to take into account words (and maybe punctuation), so that it doesn't return cut results.

I have done the following:

def split_text_to_entities(big_string)
  title = big_string(0..24)
  description1 = big_string(25..59)
  description2 = big_string(60..94)
end

But the problem with this approach is that if that if the input is "Buy our new brand shoes from our store. Best discounts in town and 40% off for first purchase.", the results would be:

title = "Buy our new brand shoes f"
description1 = "rom our store. Best discounts in to"
description2 = "wn and 40% off for first purchase."

And ideally they would be:

title = "Buy our new brand shoes"
description1 = "from our store. Best discounts in"
description2 = "town and 40% off for first"

So, try to split by character size, taking into account the words.

Community
  • 1
  • 1
blackghost
  • 683
  • 1
  • 8
  • 18
  • 1
    Have you looked at [the code for Rails' `truncate` method](http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-truncate) – sethvargo Jul 21 '14 at 18:02
  • 1
    Specifically [this code](https://github.com/rails/rails/blob/9882ec4a50eb64d1024740bbd3ebc4cf31b8e0d3/activesupport/lib/active_support/core_ext/string/filters.rb#L51-L64). – sethvargo Jul 21 '14 at 18:04

3 Answers3

2

To cover all the bases, I would do the following.

Code

def divide_text(str, max_chars)
  max_chars.map do |n|
    str.lstrip!
    s = str[/^.{,#{n}}(?=\b)/] || ''
    str = str[s.size..-1]
    s
  end
end

(?=\b) is a (zero-width) positive lookahead that matches a word break.

Examples

max_nbr_chars = [25,35,35]

str = "Buy our new brand shoes from our store. Best discounts in " +
      "town and 40% off for first purchase."    
divide_text(str, max_nbr_chars)
  #=> ["Buy our new brand shoes",
  #    "from our store. Best discounts in",
  #    "town and 40% off for first"]

str = "Buy our new brand shoes from our store."
divide_text(str, max_nbr_chars)
  #=> ["Buy our new brand shoes", "from our store.", ""]

str = "Buy our new"
divide_text(str, max_nbr_chars)
  #=> ["Buy our new", "", ""]

str = ""
divide_text(str, max_nbr_chars)
  #=> ["", "", ""]

str = "Buyournewbrandshoesfromourstore."
divide_text(str, max_nbr_chars)
  #=> ["", "Buyournewbrandshoesfromourstore.", ""]

str = "Buyournewbrandshoesfromourstoreandshoesfromourstore."
divide_text(str, max_nbr_chars)
  #=> ["", "", ""]

Note that if ^ were omitted from the regex:

str = "Buyournewbrandshoesfromourstore."
divide_text(str, max_nbr_chars)
  #=> ["ewbrandshoesfromourstore.", "rstore.", ""]
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
1

This doesn't do the trick?:

def get_chunks(str, n = 3)
  str.scan(/^.{1,25}\b|.{1,35}\b/).first(n).map(&:strip)
end
Nobita
  • 23,519
  • 11
  • 58
  • 87
  • A small problem: if the string has more than (approximately, because of `strip`) 95 characters, it will return an array containing more than three elements. I think you need to tack `[0..2]` onto the end, or somesuch. – Cary Swoveland Jul 21 '14 at 19:54
  • There may also be a problem with the last two edge cases I tested in my answer. In real life that would not be a problem with `25,35,35`, but if those values were significantly reduced it could pose a difficulty. – Cary Swoveland Jul 21 '14 at 22:51
0
s = "Buy our new brand shoes from our store. Best discounts in town and 40% off for first purchase."

s =~ /\b(.{,25})\W+(.{,35})\W+(.{,35})\b/
[$1, $2, $3] # =>
# [
#   "Buy our new brand shoes",
#   "from our store. Best discounts in",
#   "town and 40% off for first purchase"
# ]
sawa
  • 165,429
  • 45
  • 277
  • 381
  • Sawa, by doing this I would always get three chunks even if the string is short. So, for a string like this ``"Buy our new brand shoes"`` I would expect just to get one chunk with 23 size of length. I don't always need to return the three chunks, just when the previous one can't fit all the result. – blackghost Jul 21 '14 at 18:37