String#replace
str.replace(other_str) -> str The replace method swaps out a string’s entire contents with another string. Unlike sub or gsub that substitute portions matching a pattern, replace discards everything and fills the string with new content.
What makes replace unusual is that it mutates in place and returns self - the same object, not a copy. The object’s identity stays the same.
Syntax
str.replace(other_str) -> str
Parameters
| Parameter | Type | Description |
|---|---|---|
other_str | String | The string to copy into self |
Return Value
Returns self (the same string object, now holding different content). This is different from most string methods that return new objects.
Examples
Basic Usage
s = "hello"
s.replace("world")
s # => "world"
Returns Self, Not a Copy
s1 = "original"
s2 = s1.replace("modified")
s1.object_id == s2.object_id # => true (same object)
This matters when multiple variables point to the same string. After replace, all variables see the new value. After reassignment, they don’t.
Self-Assignment Is a No-Op
s = "hello"
s.replace(s) # => "hello" — no change, returns immediately
The method checks for self-assignment and returns without modifying.
Frozen Strings Raise Error
s = "hello".freeze
s.replace("world") # => FrozenError (Ruby 2.5+)
Behavior Details
Object Identity Is Preserved
replace mutates the string in place and returns self — it does not create a copy. The object_id doesn’t change. You’re not replacing the object, you’re replacing what the object contains:
buffer = "initial"
id = buffer.object_id
buffer.replace("changed")
buffer.object_id == id # => true
This is useful for reusable string buffers where you want to avoid allocations.
Taintedness Transfers
If the replacement string is tainted, the target becomes tainted:
s = "hello"
s.replace("world".taint)
s.tainted? # => true
Encoding Changes to Match Source
The encoding of self becomes the encoding of other_str:
s = "hello".encode("ASCII-8BIT")
s.replace("world".encode("UTF-8"))
s.encoding # => #<Encoding:UTF-8>
Common Patterns
Reusable String Buffer
def build_response(buffer, status, body)
buffer.replace("HTTP/1.1 #{status}\r\n")
buffer.replace(buffer + "\r\n#{body}")
end
buf = String.new
build_response(buf, 200, "OK")
In-Place Normalisation
def normalise!(str)
str.replace(str.strip.downcase)
end
data = " Hello World "
normalise!(data)
data # => "hello world"
Edge Cases
- Frozen string: Raises
FrozenError— you can’t modify a frozen string - Self-assignment: Returns immediately with no changes
- Empty string: Works fine - effectively clears the string
- Non-string argument: Calls
StringValue()which coerces viato_s
See Also
- String#sub — Replace first pattern match (returns new string)
- String#gsub! — Replace all pattern matches in place
- String#tr — Character-by-character translation
Written
- File: sites/rubyguides/src/content/reference/string-methods/string-replace.md
- Words: ~380
- Read time: 2 min
- Topics covered: replace method, mutation, object identity, frozen strings, taintedness, encoding
- Verified via: docs.ruby-lang.org/en/3.4/String.html, research.md artifact
- Unverified items: exact encoding behavior details (not deeply verified)