SCALARs and strings

chop#

Remove the last character from a string and return it.

chop shortens its argument in place by exactly one character and returns the character that was removed. It does not scan the string and does not copy it — it simply moves the end. If VARIABLE is omitted, chop operates on $_. If VARIABLE is a hash, chop chops every value of the hash (not the keys) and resets the hash’s each iterator as a side effect. Any lvalue is a valid target, including an assignment expression.

Synopsis#

chop VARIABLE
chop( LIST )
chop

What you get back#

The character that was removed, as a string. If the target was empty or undefined, the empty string is returned and the target is left unchanged. When chop is applied to a list, every element is chopped but only the character removed from the last element is returned.

my $last = chop $line;     # one character, or "" if $line was empty

Global state it touches#

Reads $_ when called with no argument. No other special variables are consulted — in particular, chop is not affected by $/ (the input record separator), which is chomp’s concern.

Examples#

Chop a scalar:

my $s = "hello";
my $c = chop $s;            # $s is now "hell", $c is "o"

Chop $_ when no argument is given — idiomatic inside a read loop that wants the terminator gone regardless of what it is:

while (<$fh>) {
    chop;                   # drops whatever character ends the line
    push @rows, $_;
}

Chop a list. Every element loses its last character; the return value is the character removed from the last element only:

my @lines = ("foo\n", "bar\n", "baz!");
my $last  = chop @lines;    # @lines is ("foo","bar","baz"), $last is "!"

Chop a hash. Values are chopped, keys are not, and the each iterator is reset:

my %h = (a => "one\n", b => "two\n");
chop %h;                    # %h is (a => "one", b => "two")

Chop an assignment — chop works on any lvalue, and an assignment returns one:

chop(my $cwd = `pwd`);      # strip the trailing newline from pwd's output

Keep all but the last character without modifying the original — not a job for chop, which mutates. Use substr with a negative length instead:

my $head = substr($s, 0, -1);   # $s is unchanged

Edge cases#

  • Empty or undefined target: returns the empty string "" and leaves the target alone. chop on undef does not raise a warning by itself; it simply produces "".

  • Read-only target: raises Modification of a read-only value attempted. This includes string literals and values flagged read-only via Internals::SvREADONLY.

  • UTF-8 strings: chop removes one character, not one byte. A multi-byte character at the end of the string is removed whole and returned as a UTF-8 string. The target’s UTF-8 flag is preserved on what remains.

  • List return value: only the character chopped from the last element is returned; the others are discarded. If you need every removed character, chop the elements individually in a loop.

  • One character vs. a line ending: chop unconditionally removes one character, whatever it is — including spaces, digits, or letters. To conditionally remove a line terminator (what $/ says one looks like), use chomp.

  • Parser parenthesisation: chop($x = $y) chops the result of the assignment, which is $x. chop $x, $y is parsed as chop($x), $y — the comma does not extend chop’s argument list without parentheses. Write chop($x, $y) when you mean the list form.

  • Hash iteration reset: because chop %h walks the values via the hash iterator, any in-progress each loop over %h is invalidated.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • chomp — conditional cousin: removes a trailing $/, not an unconditional last character; returns the number of characters removed rather than the character itself

  • substr — non-destructive alternative; substr($s, 0, -1) returns all but the last character without mutating $s

  • s///$s =~ s/.\z//s is the regex equivalent and the one chop is explicitly faster than, because chop neither scans nor copies

  • lc, uc — other in-place(ish) string transforms that accept any lvalue

  • $_ — the implicit target when chop is called with no argument

  • $/not consulted by chop; documented here only to flag the contrast with chomp