问题
def titleize(string)
nocaps = ["the","and"]
puts string.split(" ").map { |word| nocaps.include?(word) ? word : word.capitalize }.join(" ")
end
titleize("the bridge over the river kwai")
------------------------------------------------------------------------------------------
######Render => "the Bridge Over the River Kwai"
######Expected rendering => "The Bridge Over the River Kwai"
Hello i present you my piece of code, the rendering gives "the Bridge Over the River Kwai" While I would like "The Bridge Over the River Kwai" So I would like to find a way to find an exception on the same word.
回答1:
your code, but always capitalise the first letter, using each_with_index
to get the position in the array:
def titleize(string)
nocaps = ["the","and"]
string.split(" ").each_with_index.map { |word, i| i.positive? && nocaps.include?(word) ? word : word.capitalize }.join(" ")
end
titleize("the bridge over the river kwai")
回答2:
Capitalize String Before Per-Word Capitalization
There are a lot of ways to do this, but one way is to capitalize the whole String object before deciding whether or not to capitalize individual words. For example:
def titleize str
stopwords = %w[the and]
title_words = str.capitalize.split.map! do |word|
stopwords.include?(word) ? word : word.capitalize
end.join ?\s
end
p titleize("the bridge over the river kwai")
#=> "The Bridge Over the River Kwai"
p titleize("the bridge over the river kwai and the amazon")
#=> "The Bridge Over the River Kwai and the Amazon"
Under the hood this will actually downcase everything but the first letter, and then programmatically capitalize each word that isn't in stopwords. So, it relies on some implicit behavior, but works well for the examples posted.
回答3:
One way is as follows.
def titleize(str, little_words)
str.downcase.split.map.with_index do |word,i|
little_words.include?(word) && i > 0 ? word : word.capitalize
end.join(" ")
end
str = "the briDge over The river kwai"
titleize(str, ["the", "and"])
#=> "The Bridge Over the River Kwai"
Here's a second way that operates on the string directly (rather than converting it to an array or words, perform substitutions for those words and then joining the resulting array):
def titleize(str, little_words)
str.downcase.gsub(/(?<= )\p{L}+/) do |s|
little_words.include?(s) ? s : s.capitalize
end
end
titleize(str, ["the", "and"])
#=> "The Bridge Over the River Kwai"
Notice that this method preserves extra spaces between words in str
.
The regular expression reads, "match one or more Unicode letters (\p{L}+
) (greedily) preceded by a space".
A variant of this is to capitalize all words not in little_words
and then capitalize the first character of the resulting string:
def titleize(str, little_words)
str.downcase.gsub(/\p{L}+/) do |s|
little_words.include?(s) ? s : s.capitalize
end.tap { |s| s[0] = s[0].upcase }
end
See Object#tap.
If little_words
contains many words the methods could be sped up by first converting that array to a set little_words_set
(require 'set'; little_words_set = little_words.to_set
) and then substituting little_words_set
wherever little_words
now appears.
This can be improved upon by taking a page from @Todd's answer: replace downcase
with capitalize
, obviating the need for the tap
clause.
Note that little words is a term used in the publishing industry.
回答4:
While the other answers are to the point of your original post I thought I would offer another alternative using a regular expression.
def titleize(str)
nocaps = ["the","and"]
str.gsub(/\A.|\b(!?#{Regexp.union(nocaps)})\b\w+/,&:capitalize)
end
titleize("the bridge over the river and through the woods kwai")
#=> "The Bridge Over the River and Through the Woods Kwai"
This regex will select the first letter \A.
and any other words that are not contained in the nocaps
Array
then it will substitute each selected word with capitalized version.
The resulting regex in this case is /\A.|\b(?!(?-mix:the|and))\b\w+/
Example
来源:https://stackoverflow.com/questions/65782424/ruby-find-a-way-to-find-an-exception-on-the-same-word-to-capitalize