String#downcase
str.downcase(*options) -> string String#downcase returns a new string with every uppercase character converted to lowercase. The original string stays untouched. This method is useful for normalizing user input, case-insensitive comparisons, and converting text to a consistent format.
Syntax
string.downcase
string.downcase(*options)
The optional options parameter changes how Unicode characters are handled.
Parameters
| Parameter | Description |
|---|---|
*options | Optional. One or more symbols (:ascii, :turkic, :lithuanian, :fold) controlling case mapping. |
Return Value
Returns a new string. The original string is never modified. If no characters needed changing, returns self (no new object allocated).
Options
Ruby’s downcase supports several options beyond the simple A-Z mapping:
| Option | Effect |
|---|---|
:ascii | Only downcase ASCII characters A-Z. Non-ASCII Unicode letters stay unchanged. Alias: :ascii_only. |
:turkic | Apply Turkic language case rules. In Turkish, uppercase I (U+0049) becomes ı (U+0131), not i. |
:lithuanian | Apply Lithuanian-specific rules for dotted and dotless i. |
:fold | Use Unicode case folding instead of case mapping. |
You can combine :ascii or :fold with :turkic or :lithuanian. Passing incompatible combinations raises ArgumentError.
Examples
Basic usage
"Hello World".downcase
# => "hello world"
"RUBY".downcase
# => "ruby"
"PyThOn".downcase
# => "python"
Unicode characters (default behavior)
Ruby applies full Unicode case mapping by default, so accented characters convert correctly.
"ÜBER".downcase
# => "über"
"ÅNGSTRÖM".downcase
# => "ångström"
"Straße".downcase
# => "straße"
Digits, punctuation, and whitespace are left unchanged.
"NUMBERS 123".downcase
# => "numbers 123"
"symbols: !@#".downcase
# => "symbols: !@#"
The :ascii option
Sometimes you want to leave non-ASCII characters alone. Pass :ascii to restrict downcasing to ASCII letters only.
"ÜBER".downcase
# => "über"
"ÜBER".downcase(:ascii)
# => "ÜBER"
This is useful when dealing with mixed encodings or when you need to preserve accented characters as-is.
The :turkic option (Turkish locale)
Turkish has two unusual case mappings that trip up the standard approach:
- Latin uppercase
I(U+0049) → Latin lowercaseı(U+0131) — noti - Latin uppercase
İ(U+0130) → Latin lowercaseiwith dot above — noti
"ID".downcase
# => "id"
"ID".downcase(:turkic)
# => "ıd"
If you’re processing Turkish text with the default behavior, "ID".downcase gives you "id" which looks right but is technically wrong. Use :turkic when you know the locale.
"İSTANBUL".downcase
# => "istanbul" (standard)
"İSTANBUL".downcase(:turkic)
# => "ıstanbul" (Turkish correct)
Combining options
"STRİNG".downcase(:turkic, :ascii)
# => "strıng"
This applies Turkish rules for the I character, but leaves other non-ASCII characters untouched.
Unicode case folding
:fold uses Unicode case folding instead of case mapping. This is primarily useful for case-insensitive matching where you need to handle characters that have multiple possible forms.
"ß".downcase
# => "ss"
"ß".downcase(:fold)
# => "ß"
Note that :fold doesn’t normalize Unicode. A character like Å that has multiple Unicode representations may not downcase as expected if not in NFC form.
Common Patterns
Normalizing user input
def normalize_name(name)
name.downcase.strip
end
normalize_name(" ALICE ")
# => "alice"
normalize_name("Bob")
# => "bob"
Case-insensitive comparison
Downcasing both strings before comparison removes case as a factor.
query = "RUBY"
targets = ["ruby", "Rails", "Python"]
targets.any? { |t| t.downcase == query.downcase }
# => true
Safe email storage and lookup
email = "User@Example.COM"
stored_email = email.downcase
# Later, compare incoming login:
incoming = "user@example.com"
incoming.downcase == stored_email
# => true
Chaining with other methods
"POST".downcase.reverse
# => "stop"
Safe navigation
name = nil
name&.downcase
# => nil
name = "ALICE"
name&.downcase
# => "alice"
String#downcase vs String#downcase!
Ruby provides two ways to downcase a string.
| Method | Modifies original? | Return value |
|---|---|---|
downcase | No | New string (or self if no changes) |
downcase! | Yes | self or nil |
The bang version downcase! changes the string in place and returns self if changes were made, or nil if the string already contained no uppercase characters.
s = "Hello"
s.downcase!
# => "hello"
s
# => "hello"
t = "hello"
t.downcase!
# => nil
t
# => "hello"
Use downcase when you need to preserve the original string. Use downcase! when you want to modify in place and only care about the result.
Edge Cases
Empty strings
Empty strings return themselves unchanged.
"".downcase
# => ""
No uppercase characters
Strings with no uppercase letters return a new string equal to the original.
"abc".downcase
# => "abc"
"abc".downcase.equal?("abc")
# => false # a different object
The return value is always a new string object when changes occurred, but may be self when no changes were needed.
The Turkish locale trap
The most common gotcha with downcase is the Turkish I problem. In standard locales, "ID" downcases to "id". But in Turkish, the capital letter I should become ı (a lowercase i without the dot).
# Standard (works for most languages):
"ID".downcase
# => "id"
# Turkish (correct for Turkish text):
"ID".downcase(:turkic)
# => "ıd"
If you’re building systems that handle multiple languages, this matters. Use :turkic only when you know the input is Turkish—applying it blindly will give wrong results for other languages.
Lithuanian dotted i
Lithuanian has special rules for dotted and dotless i. Without the :lithuanian option, a dotted uppercase İ (U+0130) becomes a plain i, which is incorrect for Lithuanian.
# Standard (incomplete for Lithuanian):
"İ".downcase
# => "i"
# Lithuanian correct:
"İ".downcase(:lithuanian)
# => "i" (with proper Unicode rules)
Context-dependent Unicode mappings not handled
Ruby does not perform context-dependent Unicode case mapping. For example, in Greek, the lowercase of sigma depends on position: final form ς at the end of a word, regular σ elsewhere. Ruby always uses the non-final form.
# Greek sigma - Ruby always uses non-final form
"Σ".downcase
# => "σ" (not context-aware)
This is rarely a practical issue but worth knowing when working with Greek text.