Reputation: 457
When I enter as an input, "war and peace", I want, "War and Peace". The idea is to take a string and make it appear as it would as a headline or movie title. Capitalize all words in the string, unless the word is equal to or less than 3 and not in the beginning.
When I run this code:
def titleize(string)
string.split(" ").take(1).join.capitalize
string.split(" ").map do |x|
x.capitalize! if x.length > 3
end.join(" ")
end
It returns only " Peace".
Upvotes: 0
Views: 305
Reputation: 110665
There is no need to convert the string into an array of words, capitalize words having more than three characters, joining them back into a string and capitalize the first character of the resulting string. Moreover, that would strip extra spaces, which may not be desired.
Instead, one can simply use String#gsub with a regular expression to make the substitutions.
r = /
\A # match the start of the string
\p{Lower} # match a lowercase letter
| # or
(?<=[ ]) # match a space in a positive lookbehind
\p{Lower} # match a lowercase letter
(?=\p{Alpha}{3}) # match 3 letters in a positive lookahead
/x # free-spacing regex definition mode
str = "now is the time for something to happen."
str.gsub(r) { |c| c.upcase }
#=> "Now is the Time for Something to Happen."
The regex is conventionally written
/\A\p{Lower}|(?<= )\p{Lower}(?=\p{Alpha}{3})/
I used \p{Lower}
rather than \p{Alpha}
to avoid unnecessary capitalizations.
Note that in free-spacing mode the space in the positive lookbehind is enclosed in a character class ((?<=[ ])
). That's because free-spacing mode strips all spaces that are not so-protected.
Upvotes: 2
Reputation: 496
Try this:
title = 'war and peace'
def titleize(input)
input.split(' ').map.with_index { |word, index|
index == 0 || word.length > 3 ? word.capitalize : word
}.join(' ')
end
titleize title
=> "War and Peace"
Upvotes: 2
Reputation: 423
Try:
def titleize(string)
string.split.map.with_index {|x,i| if (i == 0 || x.length > 3) then x.capitalize else x end }.join(' ')
end
Note, this does not modify the string passed in, but you can do the following
foo = 'war and peace'
foo = titleize foo
puts foo
War and Peace
Upvotes: 0
Reputation: 11035
The reason you're only returning 'Peace' is because map
Invokes the given block once for each element of self.
Creates a new array containing the values returned by the block.
When you do x.capitalize! if x.length > 3
, you return nil
if the length <= 3
"war" if "war".length > 3
# => nil
So to make this work, you'll need to make sure you're returning something for each word passed to the block
def titleize(string)
string.capitalize.split.map do |x|
x.length > 3 ? x.capitalize : x
end.join(" ")
end
puts titleize("war and peace") # => "War and Peace"
Also, note that capitalize!
Modifies str by converting the first character to uppercase and the remainder to lowercase. Returns nil if no changes are made.
Whereas capitalize
Returns a copy of str with the first character converted to uppercase and the remainder to lowercase.
so x.capitalize!
could also return nil
"Peace".capitalize!
=> nil
Upvotes: 2
Reputation: 201
I would split the string into an array of strings like so:
string.split(' ')
Then capitalize each the first letter if the length of a given string is greater than 3:
for i in string.length
if string[i].length > 3
string[i].capitalize
Now just join the string:
string.join(' ')
end
Upvotes: 0