rubyguides

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

ParameterDescription
*optionsOptional. 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:

OptionEffect
:asciiOnly downcase ASCII characters A-Z. Non-ASCII Unicode letters stay unchanged. Alias: :ascii_only.
:turkicApply Turkic language case rules. In Turkish, uppercase I (U+0049) becomes ı (U+0131), not i.
:lithuanianApply Lithuanian-specific rules for dotted and dotless i.
:foldUse 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) — not i
  • Latin uppercase İ (U+0130) → Latin lowercase i with dot above — not i
"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.

MethodModifies original?Return value
downcaseNoNew string (or self if no changes)
downcase!Yesself 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.

See Also