String Methods
Every piece of text in Ruby — a name, a sentence, a line read from a file — is an instance of the String class, and String ships with dozens of methods for inspecting, transforming, and rebuilding that text. Learning these methods well is one of the highest-leverage things you can do in Ruby, because string manipulation shows up everywhere: parsing input, formatting output, cleaning user data, building reports. This lesson walks through how strings actually work under the hood and covers the methods you’ll reach for daily.
Overview / How it works
A Ruby string is a mutable, ordered sequence of characters, encoded (by default) as UTF-8. Because it’s an object, every string has methods you can call on it directly: "hello".length is a method call, not a language keyword. This is the same philosophy that makes 1.class return Integer and nil.class return NilClass — in Ruby, everything responds to messages, including a piece of text.
Strings can be created with single quotes ('text'), double quotes ("text"), or the %w/%q/%Q literal families. The difference matters: double-quoted strings support interpolation ("Hi, #{name}") and escape sequences like \n, while single-quoted strings treat almost everything literally. Prefer double quotes when you need interpolation or escapes, and either is fine for plain literal text — many style guides simply pick double quotes everywhere for consistency.
A crucial distinction runs through nearly every String method: methods that end in ! (a “bang”) mutate the string in place and return the mutated string — except when no change was made, in which case they return nil. Methods without the bang always return a brand-new string and leave the original untouched. This is not a naming convention Ruby enforces mechanically; it’s a community convention the standard library follows consistently, and understanding it prevents a whole category of bugs covered later in this lesson.
Also remember Ruby’s truthiness rule when working with string results: only nil and false are falsy. An empty string "" is truthy! If you want to check for emptiness, use .empty? explicitly rather than treating the string as a boolean.
Syntax
String methods follow the same general call pattern as any Ruby method, and some accept a block:
string.method_name(argument) { |block_variable| ... }
- string — any String instance, e.g.
"hello"or a variable holding one. - method_name — the operation to perform, such as
upcase,split, orgsub. - argument — zero or more arguments the method needs, e.g. a delimiter for
splitor a pattern forgsub. - block — optional; some methods like
gsubandeach_charyield each match or character to a block for custom processing.
Common String methods at a glance
| Method | Purpose | Mutating version |
|---|---|---|
length / size |
Number of characters | — |
upcase / downcase |
Change case | upcase! / downcase! |
capitalize |
Uppercase first letter only | capitalize! |
strip |
Remove leading/trailing whitespace | strip! |
split(sep) |
Break into an array of substrings | — |
sub(pattern, repl) |
Replace the first match | sub! |
gsub(pattern, repl) |
Replace all matches | gsub! |
include?(str) |
Does the string contain a substring? | — |
[] / slice |
Extract a substring | slice! |
reverse |
Reverse character order | reverse! |
chars |
Array of individual characters | — |
empty? |
True if length is zero | — |
Examples
Example 1: Basic transformations
name = " Ruby Programming "
puts name.length
puts name.strip
puts name.strip.upcase
puts name.downcase.strip
20
Ruby Programming
RUBY PROGRAMMING
ruby programming
The original string has two leading and two trailing spaces plus the sixteen-character phrase "Ruby Programming", giving a total length of 20. Calling .strip returns a new string with the surrounding whitespace gone — the original name variable is never modified, since strip has no bang. Chaining .upcase after .strip works because each method returns a string, so the next method in the chain has something to call itself on.
Example 2: Searching and replacing with gsub
sentence = "The rain in Spain falls mainly on the plain"
vowel_count = sentence.count("aeiouAEIOU")
puts vowel_count
capitalized = sentence.gsub(/\b\w/) { |letter| letter.upcase }
puts capitalized
no_ain = sentence.gsub("ain", "***")
puts no_ain
13
The Rain In Spain Falls Mainly On The Plain
The r*** in Sp*** falls m***ly on the pl***
count tallies how many characters in the string appear in the given character set — here, any vowel, upper or lower case, totalling 13. The gsub call with a regular expression and a block finds every character at a word boundary (\b\w) and uppercases it, effectively title-casing the sentence. The final gsub replaces every literal occurrence of "ain" with asterisks — note that gsub replaces all matches, unlike sub, which only touches the first one.
Example 3: Parsing structured text
record = "Alice, 29, Engineer | Bob, 34, Designer | Carol, 41, Manager"
people = record.split("|").map do |entry|
name, age, role = entry.split(",").map(&:strip)
"#{name} (#{age}): #{role}"
end
puts people.join("\n")
puts "Total people: #{people.length}"
Alice (29): Engineer
Bob (34): Designer
Carol (41): Manager
Total people: 3
This is the kind of realistic task string methods solve constantly: turning a flat line of text into structured data. split("|") breaks the record into three raw entries; each entry is split again on commas, and .map(&:strip) trims the stray whitespace left over from the split. The result is reassembled with string interpolation into a readable summary, then joined with newlines for display.
How it works step by step
Walking through Example 3’s pipeline shows the mechanism clearly:
- 1.
record.split("|")scans the string left to right, cutting at every|character, and returns an array of three substrings (the delimiter itself is discarded). - 2.
.mapiterates that array, calling the block once per entry and collecting each block’s return value into a new array — the original array of raw entries is never touched. - 3. Inside the block,
entry.split(",")produces a three-element array; Ruby’s multiple assignment (name, age, role = ...) unpacks it positionally into three local variables in one step. - 4.
.map(&:strip)is shorthand for.map { |s| s.strip }— the&:stripturns thestripsymbol into a block that callsstripon each element. - 5. The interpolated string
"#{name} (#{age}): #{role}"is the block’s last evaluated expression, so it’s what gets collected intopeople— a reminder that Ruby methods (and blocks) implicitly return their final expression. - 6.
people.join("\n")concatenates the array back into one string, inserting a newline between each element, ready forputs.
Common Mistakes
Mistake 1: Chaining after a bang method that returns nil
Bang methods return nil, not the string, when they make no change. Chaining another method onto that result blows up:
name = "RUBY"
result = name.upcase!.reverse
puts result
Since name is already all uppercase, upcase! makes no change and returns nil instead of the string, so calling .reverse on that nil raises NoMethodError: undefined method 'reverse' for nil:NilClass. Fix it by using the non-bang version, which always returns a string:
name = "RUBY"
upcased = name.upcase
result = upcased.reverse
puts result
YBUR
Mistake 2: Mutating a string through a shared reference
Assigning one variable to another doesn’t copy the string — both variables point at the same object in memory, so mutating one mutates both:
original = "Hello"
copy = original
copy << ", World!"
puts original
Hello, World!
The programmer likely expected original to stay "Hello", but << mutates the object in place, and copy and original are the same object. Use .dup to get an independent copy before mutating:
original = "Hello"
copy = original.dup
copy << ", World!"
puts original
puts copy
Hello
Hello, World!
Mistake 3: Reaching for sub when you meant gsub
text = "cat cat cat"
puts text.sub("cat", "dog")
dog cat cat
sub only replaces the first match, which surprises people expecting a global replace. Use gsub to replace every occurrence:
text = "cat cat cat"
puts text.gsub("cat", "dog")
dog dog dog
Best Practices
- Prefer non-bang methods by default; reach for the bang version only when you deliberately want in-place mutation and understand it can return
nil. - Use
.dupwhen you need an independent copy of a string you're about to mutate, especially one passed in as a method argument. - Use
empty?to test for an empty string rather than relying on truthiness — remember""is truthy in Ruby. - Use symbols (
:strip) with&shorthand (map(&:strip)) for simple one-method blocks; it's more idiomatic than the equivalent full block. - Add
# frozen_string_literal: trueat the top of a file to make all string literals in it frozen by default, catching accidental mutation early and improving performance. - Use
gsubwith a regular expression and a block for replacements that depend on the matched text itself, not just a fixed substitution. - Prefer interpolation (
"#{a} #{b}") over string concatenation with+for building formatted output — it's clearer and avoids type errors when a value isn't already a string.
Practice Exercises
- Write a method that takes a sentence and returns the number of words in it, without using
split's result length directly in the caller — wrap it in a method calledword_count. - Given the string
"2026-08-10", use string methods (notDate) to produce the output"10/08/2026". Hint:splitandjoinare your friends. - Write a method
shout(text)that returns the text uppercased with three exclamation marks appended, e.g.shout("ruby")should return"RUBY!!!". Then explain, in a comment, why usingupcase!instead ofupcaseinside the method would be a design mistake.
Summary
- Strings are mutable objects; every method call either mutates in place (bang methods) or returns a new string (non-bang methods).
- Bang methods return
nilwhen no change was made — never chain directly off a bang method's result. - Assignment copies the reference, not the string; use
.dupto get an independent, mutable copy. subreplaces only the first match;gsubreplaces all matches, optionally driven by a block for dynamic replacements.split,join, andstriptogether form the core toolkit for parsing and rebuilding structured text.- Only
nilandfalseare falsy in Ruby — an empty string is truthy, so test emptiness with.empty?explicitly.
