Ruby Strings
last modified October 18, 2026
Strings are one of the most used data types in Ruby. This guide covers how to write string literals, use interpolation and escape sequences, apply common String methods, format output, and understand mutability and frozen strings.
Literals and Interpolation
Ruby strings can be written with single quotes, double quotes, percent literals,
or heredocs. Double-quoted strings support interpolation with #{...}
and escape sequences such as \t, \n, and
\u. Single-quoted strings keep their contents literal, except for
\' and \\.
# Single-quoted: no interpolation, only \' and \\ escapes
name = "Alice"
single = 'Hello, #{name}!\n'
double = "Hello, #{name}!\n"
puts single
puts double.inspect
# Interpolation can hold any expression
puts "2 + 3 = #{2 + 3}"
puts "Upcase: #{name.upcase}"
# Escape sequences in double quotes
puts "Tab:\tEnd"
puts "Quote: \"hi\" and backslash: \\"
puts "Unicode: \u00e9 \u{1F600}"
# %q and %Q literals
puts %q(single-like 'quoted' #{name})
puts %Q(double-like "quoted" #{name})
# Heredoc
text = <<~TEXT
Name: #{name}
TEXT
puts text
Single quotes do not interpolate, so #{name} is printed verbatim.
Double quotes interpolate any expression and process escapes. %q
behaves like single quotes and %Q like double quotes, which is
useful when the string contains many quote characters.
$ ./literals.rb
Hello, #{name}!\n
"Hello, Alice!\n"
2 + 3 = 5
Upcase: ALICE
Tab: End
Quote: "hi" and backslash: \
Unicode: é 😀
single-like 'quoted' #{name}
double-like "quoted" Alice
Name: Alice
Common String Methods
The String class offers many methods that return new strings. Methods ending in
! modify the receiver instead. This example uses the most common
ones for measuring, changing case, trimming, splitting, replacing, searching,
slicing, and padding.
s = " Hello, Ruby World "
puts s.length # 21 (includes spaces)
puts s.strip.inspect # trims both ends
puts "hello".upcase # HELLO
puts "HELLO".downcase # hello
puts "hello world".capitalize # Hello world
puts "line\n".chomp.inspect # removes trailing newline
puts "abc".chop # removes last character
puts "a,b,c".split(",").inspect
puts %w[x y z].join("-")
puts "cat hat".sub("at", "og") # first match only
puts "cat hat".gsub("at", "og") # all matches
puts "one two three".scan(/\w+/).inspect
puts "Ruby".start_with?("Ru")
puts "Ruby".end_with?("by")
puts "Ruby".include?("ub")
puts "Ruby".index("b")
puts "Ruby Language"[0, 4] # slice by start and length
puts "Ruby Language"[5..] # slice by range
puts "stressed".reverse
puts "hi".center(10, "*")
puts "hi".ljust(6, ".") + "|"
puts "hi".rjust(6, ".")
sub replaces the first match, while gsub replaces all
matches. chomp removes a trailing newline and chop
removes the last character. center, ljust, and
rjust pad a string to a given width using an optional fill string.
scan is shown with a simple pattern only; regular expressions are
covered in a separate article.
$ ./methods.rb 21 "Hello, Ruby World" HELLO hello Hello world "line" ab ["a", "b", "c"] x-y-z cog hat cog hog ["one", "two", "three"] true true true 2 Ruby Language desserts ****hi**** hi....| ....hi
Formatting Strings
format and sprintf take a format string and values,
and String#% does the same with an array or hash argument.
Specifiers such as %s, %d, and %f
control the type, while flags and widths control padding and precision.
name = "Alice"
age = 30
price = 3.14159
# format / sprintf
puts format("Name: %s, age: %d", name, age)
puts sprintf("Price: %.2f", price)
puts format("%-8s|", "left")
puts format("%8s|", "right")
puts format("%05d", 42)
puts format("%x %o %b", 255, 8, 5)
puts format("%+d", 7)
# String#% with an array
puts "%s is %d years old" % [name, age]
# Named references
puts format("%<n>s has %<a>d items", n: "Bob", a: 3)
puts format("%{n} likes %{f}", n: "Bob", f: "pizza")
# Padding a table
[["apple", 1.5], ["kiwi", 0.25]].each do |item, cost|
puts format("%-10s $%6.2f", item, cost)
end
%-8s left-aligns and %8s right-aligns within eight
characters. %05d zero-pads, and %x, %o,
%b format integers in hexadecimal, octal, and binary. Named
references like %{name} make templates easier to read.
$ ./formatting.rb Name: Alice, age: 30 Price: 3.14 left | right| 00042 ff 10 101 +7 Alice is 30 years old Bob has 3 items Bob likes pizza apple $ 1.50 kiwi $ 0.25
Mutability and Frozen Strings
Strings are mutable by default. << appends to the same object,
so every reference sees the change. + builds a new String and
leaves the original alone. With the frozen_string_literal: true
magic comment, string literals are frozen, and modifying them raises
FrozenError. Use +"..." or String.new to
get a mutable copy, or dup to copy an existing string.
# frozen_string_literal: true
s = +"abc" # unary + returns a mutable copy
s << "def" # appends in place
puts s
a = String.new("x") # mutable copy
b = a
b << "y" # mutates the shared object
puts a # xy
c = "x" # frozen literal
d = c
d += "z" # new String; c unchanged
puts c, d # x, xz
lit = "hello"
puts lit.frozen?
begin
lit << "!"
rescue FrozenError
puts "FrozenError raised"
end
a and b reference the same object, so the append is
visible through both. d += "z" rebinds d to a new
String, leaving c unchanged. Attempting << on a
frozen literal raises FrozenError.
$ ./mutability.rb abcdef xy x xz true FrozenError raised
Source References
Learn more from these resources: Ruby String Documentation, Kernel#format, and Literals.
List all Ruby tutorials.
Author
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.