rubyguides

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