172

The upcase method capitalizes the entire string, but I need to capitalize only the first letter.

Also, I need to support several popular languages, like German and Russian.

How do I do it?

2
  • 4
    Be aware that some languages have different ideas about what the first letter to be capitalized is. In Irish, you do things like "i mBaile Átha Cliath" ("in Dublin") - lower-case 'm', upper-case 'B'. (See en.wikipedia.org/wiki/Consonant_mutation#Celtic_languages if you're curious about why Irish would do that and why it makes sense.) Commented Feb 9, 2012 at 23:19
  • 4
    And also be aware that #capitalize will downcase all letters which aren't the first letter...which is not always what you want. ['space', 'UFO', 'NASA'].collect{|w| w.capitalize} #=> ['Space', 'Ufo', 'Nasa'] Commented Nov 9, 2015 at 20:03

10 Answers 10

302

It depends on which Ruby version you use:

Ruby 2.4 and higher:

It just works, as since Ruby v2.4.0 supports Unicode case mapping:

"мария".capitalize #=> Мария 

Ruby 2.3 and lower:

"maria".capitalize #=> "Maria" "мария".capitalize #=> мария 

The problem is, it just doesn't do what you want it to, it outputs мария instead of Мария.

If you're using Rails there's an easy workaround:

"мария".mb_chars.capitalize.to_s # requires ActiveSupport::Multibyte 

Otherwise, you'll have to install the unicode gem and use it like this:

require 'unicode' Unicode::capitalize("мария") #=> Мария 

Ruby 1.8:

Be sure to use the coding magic comment:

#!/usr/bin/env ruby puts "мария".capitalize 

gives invalid multibyte char (US-ASCII), while:

#!/usr/bin/env ruby #coding: utf-8 puts "мария".capitalize 

works without errors, but also see the "Ruby 2.3 and lower" section for real capitalization.

Sign up to request clarification or add additional context in comments.

1 Comment

Note that apparently "my API is great".capitalize will produce My api is great which probably is undesired behavior. So this answer doesn't really answer the question as he only wants the FIRST letter turned to upper case and others untouched.
77

capitalize first letter of first word of string

"kirk douglas".capitalize #=> "Kirk douglas" 

capitalize first letter of each word

In rails:

"kirk douglas".titleize => "Kirk Douglas" 

OR

"kirk_douglas".titleize => "Kirk Douglas" 

In ruby:

"kirk douglas".split(/ |\_|\-/).map(&:capitalize).join(" ") #=> "Kirk Douglas" 

OR

require 'active_support/core_ext' "kirk douglas".titleize 

1 Comment

Beware of the side effect that "kirk-douglas".titleize gives "Kirk Douglas" and removes the hyphen. Think I'll go for the upcase_first method as mentioned in the Rails 5+ post, to keep the hyphen.
26

Rails 5+

As of Active Support and Rails 5.0.0.beta4 you can use one of both methods: String#upcase_first or ActiveSupport::Inflector#upcase_first.

"my API is great".upcase_first #=> "My API is great" "мария".upcase_first #=> "Мария" "мария".upcase_first #=> "Мария" "NASA".upcase_first #=> "NASA" "MHz".upcase_first #=> "MHz" "sputnik".upcase_first #=> "Sputnik" 

Check "Rails 5: New upcase_first Method" for more info.

Comments

22

Well, just so we know how to capitalize only the first letter and leave the rest of them alone, because sometimes that is what is desired:

['NASA', 'MHz', 'sputnik'].collect do |word| letters = word.split('') letters.first.upcase! letters.join end => ["NASA", "MHz", "Sputnik"] 

Calling capitalize would result in ["Nasa", "Mhz", "Sputnik"].

5 Comments

Thank you just what I was looking for, useful for converting headings to 'sentence case'
word[0] = word[0].upcase
@David. NO! That changes the values of the words in the array that #collect is called on. That is a bad side-effect.
I was showing a simpler way for capitalizing the first letter of a word, replacing the inner 3 lines of this solution, which I made clear by using the word variable. Of course, if you have more words, just call them on all of them! ;) words.map{|word| word[0] = word[0].upcase}
@David. Your code amounts to #capitalize! and not #capitalize. The latter returns a new String while the former modifies the receiver of the method (in this case the receiver is word and the method is #[]). If you used your code inside of a #collect block then you'd end up with two different arrays with the same String objects in each of them (and the Strings would have been modified). That is not something you'd normally want to do. Even if you're aware of this, other readers should understand this.
20

Unfortunately, it is impossible for a machine to upcase/downcase/capitalize properly. It needs way too much contextual information for a computer to understand.

That's why Ruby's String class only supports capitalization for ASCII characters, because there it's at least somewhat well-defined.

What do I mean by "contextual information"?

For example, to capitalize i properly, you need to know which language the text is in. English, for example, has only two is: capital I without a dot and small i with a dot. But Turkish has four is: capital I without a dot, capital İ with a dot, small ı without a dot, small i with a dot. So, in English 'i'.upcase # => 'I' and in Turkish 'i'.upcase # => 'İ'. In other words: since 'i'.upcase can return two different results, depending on the language, it is obviously impossible to correctly capitalize a word without knowing its language.

But Ruby doesn't know the language, it only knows the encoding. Therefore it is impossible to properly capitalize a string with Ruby's built-in functionality.

It gets worse: even with knowing the language, it is sometimes impossible to do capitalization properly. For example, in German, 'Maße'.upcase # => 'MASSE' (Maße is the plural of Maß meaning measurement). However, 'Masse'.upcase # => 'MASSE' (meaning mass). So, what is 'MASSE'.capitalize? In other words: correctly capitalizing requires a full-blown Artificial Intelligence.

So, instead of sometimes giving the wrong answer, Ruby chooses to sometimes give no answer at all, which is why non-ASCII characters simply get ignored in downcase/upcase/capitalize operations. (Which of course also reads to wrong results, but at least it's easy to check.)

2 Comments

Sorry, but your argumentation doesn't hold water. It is not true that Ruby chooses not to give an answer at all, Ruby always gives an answer, which often is wrong - e.g. "мария".upcase should never return "мария", that is not correct in any context. And your digressions about the need for AI is not relevant at all - there is nothing that prevents upcase returing an array, say ['I', 'İ'] for 'i'.upcase, and letting the caller decide which capitalization is relevant in a given situation. Currently the Ruby's handling of conversion between upper- and lowercase is broken, and that's it.
-1 because there is a capital Eszett. Using some non completely formalized area can not serve as proof of that solution is possible with AI only.
6

Use capitalize. From the String documentation:

Returns a copy of str with the first character converted to uppercase and the remainder to lowercase.

"hello".capitalize #=> "Hello" "HELLO".capitalize #=> "Hello" "123ABC".capitalize #=> "123abc" 

4 Comments

Only use the exclamation point if you want the original string to be changed.
-1. The OP explicitly mentions German and Russian text, which implies non-ASCII characters. String#upcase (and also String#downcase) are only defined for ASCII characters.
Using Ruby 2.5.0 today and String#upcase seems to work fine on non-ASCII characters. 2.5.0 :001 > "мария".upcase => "МАРИЯ"
@Huliax As mentioned in the accepted answer, that has only been the case since Ruby 2.4.0 (which was released in 2016).
4

My version:

class String def upcase_first return self if empty? dup.tap {|s| s[0] = s[0].upcase } end def upcase_first! replace upcase_first end end ['NASA title', 'MHz', 'sputnik'].map &:upcase_first #=> ["NASA title", "MHz", "Sputnik"] 

Check also:
https://www.rubydoc.info/gems/activesupport/5.0.0.1/String%3Aupcase_first
https://www.rubydoc.info/gems/activesupport/5.0.0.1/ActiveSupport/Inflector#upcase_first-instance_method

Comments

3

You can use mb_chars. This respects umlaute:

class String # Only capitalize first letter of a string def capitalize_first self[0] = self[0].mb_chars.upcase self end end 

Example:

"ümlaute".capitalize_first #=> "Ümlaute" 

Comments

3

This is another way to only convert the first character of a string to uppercase:

"striNG".sub(/./, &:upcase) => "StriNG" 

Each word can be capitalized too using the following methods:

\w doesn't match Cyrillic characters or Latin characters with diacritics but [[:word:]] does. upcase, downcase, capitalize, and swapcase didn't apply to non-ASCII characters until Ruby 2.4.0 which was released in 2016.

"aAa-BBB ä мария _a a_a".gsub(/\w+/, &:capitalize) => "Aaa-Bbb ä мария _a A_a" "aAa-BBB ä мария _a a_a".gsub(/[[:word:]]+/, &:capitalize) => "Aaa-Bbb Ä Мария _a A_a" 

[[:word:]] matches characters in these categories:

Ll (Letter, Lowercase) Lu (Letter, Uppercase) Lt (Letter, Titlecase) Lo (Letter, Other) Lm (Letter, Modifier) Nd (Number, Decimal Digit) Pc (Punctuation, Connector) 

[[:word:]] matches all 10 of the characters in the "Punctuation, Connector" (Pc) category:

005F _ LOW LINE 203F ‿ UNDERTIE 2040 ⁀ CHARACTER TIE 2054 ⁔ INVERTED UNDERTIE FE33 ︳ PRESENTATION FORM FOR VERTICAL LOW LINE FE34 ︴ PRESENTATION FORM FOR VERTICAL WAVY LOW LINE FE4D ﹍ DASHED LOW LINE FE4E ﹎ CENTRELINE LOW LINE FE4F ﹏ WAVY LOW LINE FF3F _ FULLWIDTH LOW LINE 

Comments

1

If you want to capitalize only the first character in a string in ruby, as the author requested, you should just do exactly that:

word[0] = word[0].upcase 

This works for all languages and only touches the first letter of the entire string.

word = "мария" # => "мария" word[0] = word[0].upcase # => "М" word # => "Мария" 

It does not require Rails or any other libary.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.