String#chop
chop removes the last character from a string, or the CRLF (\r\n) pair if the string ends with one. Unlike chomp, which only strips line endings, chop removes any trailing character unconditionally.
Signature
str.chop → new_string
Returns: A new string with the last character removed.
Basic Behavior
# Remove the last character
"hello".chop
# => "hell"
# Handles CRLF as a pair
"hello\r\n".chop
# => "hello"
# CRLF counts as two characters removed
"hello\r\n\r\n".chop
# => "hello\r\n"
When the string ends with \r\n, both characters are removed together. Otherwise, just the final character goes:
# Only removes the last character
"hello\n".chop
# => "hello\n" (LF is just another character)
# Empty string stays empty
"".chop
# => ""
The Bang Variant
chop! modifies the receiver in place:
s = "hello"
s.chop!
# => "hell"
s
# => "hell"
# Returns nil on empty string (no modification possible)
"".chop!
# => nil
chop vs chomp
This is the key difference: chomp only removes line endings (\n, \r, or \r\n), while chop removes any trailing character:
# chomp targets line endings specifically
"hello\n".chomp
# => "hello"
# chop removes any character
"hello\n".chop
# => "hell"
# chomp on a string with no line ending returns unchanged
"hello".chomp
# => "hello"
# chop always removes one character (or two for CRLF)
"hello".chop
# => "hell"
Practical Examples
Path Manipulation
# Remove a trailing slash from a path
"/usr/local/bin/".chop
# => "/usr/local/bin"
# Remove trailing slashes recursively
path = "/api/v1/users/"
path.chop while path.end_with?("/")
# => "/api/v1/users"
Reading Lines the Unix Way
Before Ruby had chomp, programmers used chop to clean up lines from files:
# Old school line reading (still works)
File.read("data.txt").each_line do |line|
puts line.chop
end
Note that chop is not safe for lines that legitimately end with CRLF — use chomp for that.
Removing Trailing Newlines Safely
# User input might end with \n or \r\n or neither
input = gets.chop # Always removes the last character
# If you only want to remove line endings:
input = gets.chomp
Common Pitfalls
Removing More Than Intended
If a string doesn’t end with a newline, chop still removes a character:
# You meant to remove a newline, but there's none:
"hello".chomp
# => "hello" (safe, no-op)
"hello".chop
# => "hell" (oops, you just removed a letter)
CRLF Double Removal
If you combine chomp with chop, you might remove too much:
# Two operations on CRLF line ending:
"hello\r\n".chomp.chop
# => "hel" -- removed both \r\n AND the 'l'!
Empty String Handling
chop! returns nil on empty strings, which surprises people in conditionals:
# This conditional is wrong:
if str.chop!
# nil is falsy, so this branch won't run even though chop! succeeded
# (unless the string was empty, in which case nil is correct)
end
# Correct:
result = str.chop!
if result
# worked
end
Binary Data
chop treats bytes as characters, which causes problems with multi-byte encodings:
# UTF-8 string
"héllo".chop
# => "hell" -- removed the accent, not the 'o'
# For binary strings, use slicing instead
s = "\xfe\xff\x00"
s[0...-1]
# => "\xfe\xff"
See Also
- /reference/string-methods/chomp/ — remove trailing line endings (\n, \r, \r\n)
- /reference/string-methods/chop-bang/ — modify in place, returns nil on empty
- /reference/string-methods/strip/ — remove leading and trailing whitespace