String Methods

Published by Programming Line in Ruby. Last updated .

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, or gsub.
  • argument — zero or more arguments the method needs, e.g. a delimiter for split or a pattern for gsub.
  • block — optional; some methods like gsub and each_char yield 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. .map iterates 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 &:strip turns the strip symbol into a block that calls strip on each element.
  • 5. The interpolated string "#{name} (#{age}): #{role}" is the block’s last evaluated expression, so it’s what gets collected into people — 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 for puts.

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 .dup when 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: true at the top of a file to make all string literals in it frozen by default, catching accidental mutation early and improving performance.
  • Use gsub with 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 called word_count.
  • Given the string "2026-08-10", use string methods (not Date) to produce the output "10/08/2026". Hint: split and join are 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 using upcase! instead of upcase inside 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 nil when no change was made — never chain directly off a bang method's result.
  • Assignment copies the reference, not the string; use .dup to get an independent, mutable copy.
  • sub replaces only the first match; gsub replaces all matches, optionally driven by a block for dynamic replacements.
  • split, join, and strip together form the core toolkit for parsing and rebuilding structured text.
  • Only nil and false are falsy in Ruby — an empty string is truthy, so test emptiness with .empty? explicitly.