Explantion on the use of chop() and chomp() functions.

In an effort to learn Perl I was going through the Llama book. When I came to the second chapter there was an exercise where we need to enter two numbers and the program will return their product. I did the program and it worked well except for a small glitch. Here is my code and the output.

#!/usr/bin/perl
print "Enter the first number : ";
$num1 = <STDIN>;
print "Enter the second number : " ;
$num2 = <STDIN>;
$prd = $num1 * $num2;
print "The product of $num1 and $num2 is $prd\n";

The code worked well and outputted 20 if we enter 4 and 5 but it printed output like this.

Enter the first number : 4
Enter the second number : 5
The product of 4
and 5
is
20

Now it was annoying. Having only started programming in Perl and my previous experience in C or Java or even PHP never made me expect something like this. I expected it to print the whole sentence in one single line. What could be wrong. Then I recalled Llama telling about <STDIN> adding a ‘\n’ to the input and the need for using chomp() to get rid of this.

So I modified code and added two more lines

chomp($num1);
chomp($num2);

This made it correct. But still I found it odd and thought this feature of <STDIN> a nuisance. So I went into some knowledge hunting. I asked in #perl channel at freenode. So far I was wary and wasn’t talking and was merely listening. I was afraid even while asking this of getting some serious ‘RTFM’. But the folk in there responded nicely. Thanks for <claes_>. He gave the apt reply. Here is what I learned from him.

There is a special variable in Perl named $/ which is initialzed to be ‘\n’. This variable is termed the input record separator. This variable is used to separate the various lines from your inut. Since $/ contains ‘\n’ it assumes your input has been ended once you key in the return key.(Note: Though the ‘\n’ is not a part of the intended input, since you entered it it will also be included as a part of your input). That’s why we get the newline when printing it back. When we use chomp() it removes these ‘\n’. If we explicitly assign say, ‘f’ to $/ then <STDIN> enters whatever up to the first ‘f’ it sees. Also the functionality of chomp() changes. It will now remove the last ‘f’ from your input (Once again though ‘f’ wasn’t in your intended input, since you entered it it would be there, Please don’t do so. Leave ‘$/’ to the ‘/n’, or be ready to bear the dire after effects). So $/ variable helps in entering user input from standard input.

Another option is to use in the above example is the chop() method [I earlier called it a better option, but I taking that away as per the info by ‘Andrew’]. When chomp() removes whatever declared in the $/ variable, chop() removes the last character from the input.

So in the below snippet
$str = "Christy;
chop($str);
print $str;

the output is ‘Christ’;

I think I was successful in explaining the issue and let this save another newbie someday.

[Revision: Thursday 3 Sep, 2009, There was some confusion in the explanation of input record separator. Thank to Chas Owen. I corrected it.}

add to del.icio.us : Add to Blinkslist : add to furl : Digg itStumble It! : add to simpy : seed the vine : : : TailRank : post to facebook

Advertisements

12 thoughts on “Explantion on the use of chop() and chomp() functions.

  1. It is import to note that <STDIN> is not adding the newlines, it is not stripping them. They are already in the file being read (in this case they are put there by your hitting the enter key). You can see the behavior clearly in this sample code:

    perl -e ‘print “foo\nbar\nbaz”‘ | perl -ne ‘s/\n/CR/;print “[$_]\n”‘

    The last line does not have a newline character, and it does not show up in the output.

    1. I’m not completely aware of what you have said as I’m still learning. Anyway I assume <STDIN> confirms that you have entered the input once you have enter the return key.
      However I ran the below code and it is outputting a new line so what I said should be correct
      #!/usr/bin/perl
      print $/;

      But I’ll read the documentation and look into it deeper and change the post if there is anything wrong.
      Anyway thanks for dropping in.

      1. The input record separator ($/) does in fact contain “\n” by default. That is why the readline operator () returns lines, but the readline operator does not add “\n” to lines. That character is already part of the line in the file you are reading from. STDIN is no different from any other file. Press enter is not some magic thing that cause Perl to read the line. Pressing enter generates a newline. Perl sees the newline (just like it sees every character), compares it to what is currently set in $/, sees that they are the same, so it returns the string including the “\n” that you — not the readline operator — put there.

        If you were to set the input record separator to “\n===\n” then it would return a multi-line string that ends with “\n===\n” (or the entire file if it doesn’t contain “\n===\n”). Try this on the commandline:

        perl -e ‘$/ = “\n===\n”; my $record = ; print “I saw: $record”‘

        Type as much as you want, hit enter as many times as you want. Then (after hitting enter) type === and hit enter. The program will print back what you typed.

  2. Drat the lack of a preview option. All of my angle brackets were interpreted as HTML. Here it is again with entities instead:

    The input record separator ($/) does in fact contain “\n” by default. That is why the readline operator (<>) returns lines, but the readline operator does not add “\n” to lines. That character is already part of the line in the file you are reading from. STDIN is no different from any other file. Pressing enter is not some magic thing that cause Perl to read the line. Pressing enter generates a newline. Perl sees the newline (just like it sees every character), compares it to what is currently set in $/, sees that they are the same, so it returns the string including the “\n” that you — not the readline operator — put there.

    If you were to set the input record separator to “\n===\n” then it would return a multi-line string that ends with “\n===\n” (or the entire file if it doesn’t contain “\n===\n”). Try this on the commandline:

    perl -e ‘$/ = “\n===\n”; my $record = <STDIN>; print “I saw: $record”‘

    Type as much as you want, hit enter as many times as you want. Then (after hitting enter) type === and hit enter. The program will print back what you typed.

    1. exactly, that is what I said when I said If we explicitly assign ‘f’ to ‘$/’ the line will end where it first sees a n ‘f’.

    2. Thanks Chas for pointing out. i made some revisions. I believe now the explanation is correct. But please check, if there is still corrections to be done, I’ll.

  3. Chop isn’t really “better”. If you’re using <> you should always be using chomp with it, because they both use $/ in the same way. <> reads everything up to and including the record separator, and chomp removes the record separator. If you use chomp, your code will do the right thing whether $/ is “\n” or “\r\n” or “\n–\n” or \4096. If you use chop, it won’t always work.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s