String#swapcase with Unicode Options
str.swapcase(*options) → string String#swapcase returns a new string with the case of each character reversed. Every uppercase character becomes lowercase, and every lowercase character becomes uppercase. This is useful for stylistic transformations, display formatting, or when you need to toggle case without normalizing to a specific case.
It is a handy way to make a string visibly different without changing its length or structure. That can help in small text transforms, debugging output, or demonstrations where you want the effect to be obvious at a glance.
The method is handy when you want a quick visual change without writing a custom character-mapping routine.
Syntax
str.swapcase
str.swapcase(*options)
The optional options parameter accepts symbols that change how Unicode characters are handled. Ruby 3.0 introduced :ascii, which restricts swapping to A–Z and a–z, and :turkic, which applies Turkish-specific rules for dotted and dotless I. You can pass multiple options at once when you need combined behaviour, and without any options the method defaults to full Unicode case mapping covering every script with defined case pairs.
Basic Usage
"Hello".swapcase
# => "hELLO"
"world".swapcase
# => "WORLD"
"RuBy".swapcase
# => "rUbY"
The original string is never modified: swapcase follows the standard Ruby convention where methods without a bang return a new object while leaving the receiver untouched. Internally, the method allocates a fresh string and writes the case-swapped result into it. The original retains its identity, content, and encoding unchanged. This non-mutating behaviour matters for functional-style code and any situation where you need both the original and swapped versions.
original = "Hello"
result = original.swapcase
original
# => "Hello"
result
# => "hELLO"
Non-alphabetic characters are left unchanged: digits, punctuation marks, whitespace, mathematical symbols, and any Unicode code point without a defined case mapping all pass through without modification. The method inspects each character against the Unicode Character Database and only transforms those belonging to a letter category with both uppercase and lowercase variants. You can safely call swapcase on strings that mix letters with numbers, emoji, or CJK characters.
"123abc!@#".swapcase
# => "123ABC!@#"
"foo.bar".swapcase
# => "FOO.BAR"
Unicode case mapping
From Ruby 3.0 onward, swapcase uses full Unicode case mapping by default. This means accented characters and non-ASCII letters are handled. Ruby consults the Unicode Character Database, so accented Latin letters like é, ñ, ü, Greek letters such as α ↔ Α, and Cyrillic letters like д ↔ Д all swap correctly. Multi-character mappings are also supported — the German eszett ß uppercases to SS without altering the string’s byte length unexpectedly:
"Über".swapcase
# => "üBER"
"Ångström".swapcase
# => "åNGSTRÖM"
"Straße".swapcase
# => "sTRASSEN"
Characters that have no case variant stay unchanged: CJK ideographs, Arabic script, emoji, mathematical operators, and many symbol blocks lack separate case forms in Unicode. Digits and punctuation are similarly unaffected since they are not classified as cased letters. This design means you never need to pre-filter a string before calling swapcase; the method gracefully handles any mix of content.
"123".swapcase
# => "123"
ASCII-only conversion
Use :ascii when you only want a-z and A-Z swapped, leaving all other characters untouched. The :ascii option limits case conversion to code points 0x41–0x5A and 0x61–0x7A, the classic ASCII letter ranges. This is helpful with legacy protocols that expect ASCII-only output or when you need predictable results across Ruby installations with different Unicode versions. Characters outside the ASCII letter range, including Latin-1 supplements like ü and Ö, are copied to the output unchanged:
"Über".swapcase
# => "üBER"
"Über".swapcase(:ascii)
# => "üBER"
In this case, ü and Ö are outside the ASCII range, so they are not affected. The :ascii option is useful when you are working with mixed encodings or when non-ASCII characters should be preserved as-is.
Turkic case mapping
Turkish distinguishes dotted and dotless I. Use :turkic when processing Turkish text:
"ID".swapcase
# => "id"
"ID".swapcase(:turkic)
# => "ıd"
The standard swapcase converts I to ı (lowercasing) and D to d, giving "ıd". With :turkic, Ruby applies the correct Unicode case mapping for Turkish — uppercase dotted I (U+0130) becomes lowercase dotless ı (U+0131), not a regular i.
In-Place Swapping
Use swapcase! when you want to mutate the receiver:
text = "Hello"
text.swapcase!
# => "hELLO"
text
# => "hELLO"
swapcase! returns self if changes were made, or nil if the string was already in the target case. This nil-on-no-change convention is shared by all String bang methods — upcase!, downcase!, capitalize!, and swapcase! — and lets you write conditional logic that only acts when a mutation occurred. For strings containing only digits or caseless characters, swapcase! returns nil immediately:
"hello".swapcase!
# => "HELLO"
"HELLO".swapcase!
# => nil
Common Patterns
Toggle case for display
The patterns in this section show practical ways to use swapcase inside larger Ruby programs. The first pattern toggles case as a quick visual transformation — useful when you want to draw attention to text in a CLI tool, generate alternate renderings of labels, or produce visibly distinct output without altering string length. Passing &:swapcase to map applies the transformation to every element in a collection with a single concise expression.
labels = ["name", "Email", "Phone"]
labels.map(&:swapcase)
# => ["NAME", "eMAIL", "pHONE"]
Process mixed-case identifiers
Swapping case provides a lightweight way to transform identifiers in Ruby. When you have mixed-case tokens — perhaps from combining user input with system constants — swapcase produces a consistent alternate form without destroying the original case information. This technique is useful in testing helpers, unique-key generation, and any context where you need a reversible character-by-character transformation.
def normalize_id(id)
id.swapcase
end
normalize_id("User123")
# => "uSER123"
Check case-swapped equality
A third pattern uses swapcase to test whether two strings are case-swapped versions of each other. By swapping the case of one string and comparing it to the second, you can detect intentional case inversion — a check that comes up in password validation, input normalisation, and fuzzy-matching routines. The comparison is strict equality, so it also confirms that the strings have identical length and non-alphabetic character content.
a = "Hello"
b = "hELLO"
a.swapcase == b
# => true
Edge Cases
Empty strings
Edge cases matter for defensive Ruby code, and swapcase handles them predictably. An empty string returns another empty string because the method iterates over characters and finds none to transform. The return value is a new empty string object — not the same object — which matches the non-mutating contract of swapcase. This consistent behaviour means you can call swapcase on any string without a guard clause checking for zero length first.
"".swapcase
# => ""
No alphabetic characters
Strings that contain no cased letters — only digits, symbols, or whitespace — return themselves unchanged. Ruby scans every character, determines that none have an uppercase or lowercase counterpart in the Unicode database, and produces an output string that is byte-for-byte identical to the input. This is a no-op scenario, but knowing it works without errors means you can safely pipe untrusted or unknown content through swapcase without pre-validation.
"123!@#".swapcase
# => "123!@#"
Turkish locale sensitivity
The Turkish locale has unusual case-mapping rules for I and İ. Always use :turkic when processing Turkish text. In Turkish, uppercase i (U+0069) becomes İ (dotted capital I), while lowercase I (U+0049) becomes ı (dotless i). These differ from the standard mapping where i ↔ I. Without :turkic, Ruby produces incorrect Turkish output. The example below shows both behaviours:
# Standard behavior (wrong for Turkish):
"İstanbul".swapcase
# => "ıSTANBUL" — dotted İ becomes ı, but should become i
# With Turkic option (correct for Turkish):
"İstanbul".swapcase(:turkic)
# => "i̇stanbul" — dotted İ becomes i with combining dot above
Characters without case mapping
Some Unicode characters do not have a case variant. These pass through unchanged. Chinese, Japanese, and Korean characters, emoji, mathematical symbols, arrows, and geometric shapes all lack case variants in Unicode. The method is safe to call on any string; characters without case data pass through unchanged:
"日本".swapcase
# => "日本"
The swapcase method also works correctly with frozen string literals and encodings beyond UTF-8. When the frozen string literal pragma is active, swapcase still returns a new unfrozen string with the swapped case since Ruby allocates a fresh object for the output. Encoding is preserved through the transformation, and swapcase handles ASCII-8BIT and other encodings without raising:
# frozen_string_literal: true
enc = "RUBY".encode("ASCII-8BIT")
result = enc.swapcase
result.encoding
# => #<Encoding:ASCII-8BIT>
result
# => "ruby"
See Also
- String#upcase — convert all characters to uppercase
- String#downcase — convert all characters to lowercase
- String#capitalize — uppercase first character, lowercase the rest