06 · Strings & String Methods¶
String basics¶
s = "Hello, World!"
puts s.downcase # hello, world!
puts s.upcase # HELLO, WORLD!
puts s.length # 13
puts s[7..11] # World -- inclusive range slice
puts s.reverse # !dlroW ,olleH
puts s.split(", ") # ["Hello", "World!"]
puts ["a", "b", "c"].join(" ") # a b c
puts " padded ".strip # "padded" -- removes leading/trailing whitespace
String interpolation vs concatenation¶
name = "Ada"
age = 30
# Interpolation -- the idiomatic Ruby way, only works in double-quoted strings
puts "#{name} is #{age} years old"
# Concatenation
puts name + " is " + age.to_s + " years old"
# << appends in place (mutates the original string)
greeting = "Hello"
greeting << ", " << name << "!"
puts greeting # Hello, Ada!
'single quotes' do not interpolate — '#{name}' prints literally as
#{name}. Always use double quotes when you need #{...} interpolation.
Formatting numbers into strings¶
pi = 3.14159265
puts "pi rounded: %.2f" % pi # pi rounded: 3.14
puts format("%.2f", pi) # 3.14 -- equivalent, more explicit
puts "%5d" % 42 # " 42" -- right-aligned in width 5
name = "Ada"
puts "Name: #{name.ljust(10)}|" # "Name: Ada |"
Multi-line and heredoc strings¶
paragraph = "This spans
multiple lines."
# Heredoc -- common for larger blocks of text
sql = <<~SQL
SELECT *
FROM users
WHERE active = true
SQL
puts sql
<<~ (squiggly heredoc) automatically strips the leading indentation from
each line, which keeps the heredoc readable even when nested inside
indented code.
Common string checks¶
"42".match?(/\A\d+\z/) # true -- regex match
"hello".start_with?("he") # true
"hello".end_with?("lo") # true
" ".strip.empty? # true
"Hello, World!".include?("World") # true
String immutability (mostly)¶
s = "hello"
s.upcase # returns "HELLO" but doesn't change s
puts s # hello -- unchanged
s.upcase! # mutates s in place (bang version)
puts s # HELLO
Ruby strings are technically mutable objects (unlike Python/Java strings),
but non-bang methods like .upcase return a new string rather than
modifying the receiver — you must call the ! version, or reassign, to
actually change the original.
How It Actually Works¶
Ruby strings are mutable byte buffers with an attached Encoding object
(UTF-8 by default) — internally a String is a struct holding a pointer to
a heap buffer, a length, and a capacity, much like a C string but
length-prefixed rather than null-terminated, so "a\0b".length is 3, not 1.
Every string method that "changes" a string either mutates that buffer in
place (<<, gsub!, concat — no new object, same object_id) or
allocates a fresh buffer and returns a new String (+, gsub, upcase).
Since Ruby 3.0, string literals aren't frozen by default, but MRI still
deduplicates identical frozen string literals when you add
# frozen_string_literal: true at the top of a file — the interpreter
interns them once, similar to Symbols, saving both memory and repeated
allocation for strings that never need to change.
Cheat sheet¶
| Task | Method |
|---|---|
| Interpolate a value | "text #{expr} text" |
| Format a float | "%.2f" % value or format("%.2f", value) |
| Multi-line literal text | <<~LABEL ... LABEL (heredoc) |
| Check substring | .include?, .start_with?, .end_with? |
| Regex match | .match?(/pattern/) |
| Mutate in place | Bang methods: .upcase!, .strip!, etc. |
🔀 See this in another language¶
- PHP — Strings & String Functions
- MATLAB — Plotting & Visualization Basics
- JavaScript — Strings & Template Literals
Exercise¶
Write a method slugify(title) that converts "Hello, World! " into
"hello-world" — lowercase, punctuation stripped (hint: gsub with a
regex), spaces replaced with hyphens, and any leading/trailing hyphens
stripped.