3

I found a strange behavior of chomp in Perl and I am unable to comprehend why is chomp is working like this.

The following line does not work as expected

if ( chomp($str1) eq chomp($str2) )

But, the following works fine

chomp $str1;
chomp $str2;
if ( $str1 eq $str2 )

Can you please give some insight in this behavior of chomp?

Bill
  • 5,263
  • 6
  • 35
  • 50

4 Answers4

12

chomp modifies its argument. It does not return a modified argument. The second example is, in fact, how you're supposed to use it.

edit: perldoc -f chomp says:

   chomp   This safer version of "chop" removes any trailing string that
           corresponds to the current value of $/ (also known as
           $INPUT_RECORD_SEPARATOR in the "English" module).  It returns
           the total number of characters removed from all its arguments.
  • 1
    +1. To be more explicit: `chomp` takes one or more arguments, modifies them if necessary, and "returns the total number of characters removed from all its arguments". [[link](http://perldoc.perl.org/functions/chomp.html)] – ruakh Feb 14 '12 at 02:34
  • I have always thought that there should be an `rchomp` which behaves as the OP expected. I think that `chomp( my $input = <> );` looks really awkward, wouldn't you rather `my $input = rchomp <>` – Joel Berger Feb 14 '12 at 02:45
  • 1
    I hate these C-style interfaces that modify arguments. [Text::Chomped](http://p3rl.org/Text::Chomped) is the work-around. – daxim Feb 14 '12 at 11:08
  • 1
    The original idea behind modifying it in place is that you can write your perl script with implicit arguments (`$_`) and have it all like `while() { chomp; next if /begin_pattern/../end_pattern/; s/x/y/; print; }` -- that's where Perl comes from, historically, and that's the source of most of the things people find quirky. I agree that it's dubious in most modern programming, though. –  Feb 14 '12 at 16:59
2

chomp returns the number of characters removed, not the strings that have been chomped.

evil otto
  • 10,348
  • 25
  • 38
2

I like the name chomp() it's sound tells you what it does. As @ruakh mentions it takes one or more arguments, so you can say:

chomp($str1,$str2);
if ( $str1 eq $str2 ) ...

You can also hand it an array of strings, like what you would get from reading a whole file at once, e.g.:

chomp(@lines);
tangent
  • 551
  • 1
  • 3
  • 7
0

Generally, you can use s,$/$,,r regex as a non-destructive chomp. It removes record separator $/ from the end of $_ or the string provided using =~, and returns the result without modifying anything. Your example would look like this:

if ( $str1 =~ s,$/$,,r eq $str2 =~ s,$/$,,r )

More formally the regex should be s,\Q$/\E$,,r, so $/ is not treated as regex. In paragraph mode the regex would need to be s,\n*$,,r. In slurp or fixed record mode the regex is not needed at all (chomp does nothing).

mik
  • 3,575
  • 3
  • 20
  • 29