7

I'm on break from classes right now and decided to spend my time learning Perl. I'm working with Beginning Perl (http://www.perl.org/books/beginning-perl/) and I'm finishing up the exercises at the end of chapter three.

One of the exercises asked that I "Store your important phone numbers in a hash. Write a program to look up numbers by the person's name."

Anyway, I had come up with this:

#!/usr/bin/perl
use warnings;
use strict;

my %name_number=
(
Me => "XXX XXX XXXX",
Home => "YYY YYY YYYY",
Emergency => "ZZZ ZZZ ZZZZ",
Lookup => "411"
);

print "Enter the name of who you want to call (Me, Home, Emergency, Lookup)", "\n";
my $input = <STDIN>;
print "$input can be reached at $name_number{$input}\n";

And it just wouldn't work. I kept getting this error message:

Use of uninitialized value in concatenation (.) or string at hello.plx line 17, line 1

I tried playing around with the code some more but each "solution" looked more complex than the "solution" that came before it. Finally, I decided to check the answers.

The only difference between my code and the answer was the presence of chomp ($input); after <STDIN>;.

Now, the author has used chomp in previous example but he didn't really cover what chomp was doing. So, I found this answer on www.perlmeme.org:

The chomp() function will remove (usually) any newline character from the end of a string. The reason we say usually is that it actually removes any character that matches the current value of $/ (the input record separator), and $/ defaults to a newline..


Anyway, my questions are:

  1. What newlines are getting removed? Does Perl automatically append a "\n" to the input from <STDIN>? I'm just a little unclear because when I read "it actually removes any character that matches the current value of $/", I can't help but think "I don't remember putting a $/ anywhere in my code."

  2. I'd like to develop best practices as soon as possible - is it best to always include chomp after <STDIN> or are there scenarios where it's unnecessary?

Cœur
  • 37,241
  • 25
  • 195
  • 267
krebshack
  • 992
  • 1
  • 9
  • 19
  • 2
    `perldoc -f chomp` or [perlfunc](http://perldoc.perl.org/perlfunc.html) –  Sep 03 '11 at 00:59
  • Okay, so the chomp entry in Perlmeme's FAQ (http://www.perlmeme.org/faqs/manipulating_text/chomp.html) answers most of my first question. That is, the FAQ leads me to believe that Perl does automatically a newline (not necessarily at "\n" but a newline just the same). But am I understanding that correctly? – krebshack Sep 03 '11 at 01:00
  • Continuing with the link from perlfunc: [chomp](http://perldoc.perl.org/functions/chomp.html) which covers the use of the separator. –  Sep 03 '11 at 01:01
  • Oh, thank you for the perlfunc link. That'll be a really helpful resource in the future. – krebshack Sep 03 '11 at 01:05

5 Answers5

9

<STDIN> reads to the end of the input string, which contains a newline if you press return to enter it, which you probably do.

chomp removes the newline at the end of a string. $/ is a variable (as you found, defaulting to newline) that you probably don't have to worry about; it just tells perl what the 'input record separator' is, which I'm assuming means it defines how far <FILEHANDLE> reads. You can pretty much forget about it for now, it seems like an advanced topic. Just pretend chomp chomps off a trailing newline. Honestly, I've never even heard of $/ before.

As for your other question, it is generally cleaner to always chomp variables and add newlines as needed later, because you don't always know if a variable has a newline or not; by always chomping variables you always get the same behavior. There are scenarios where it is unnecessary, but if you're not sure it can't hurt to chomp it.

Hope this helps!

smackcrane
  • 1,379
  • 2
  • 10
  • 17
  • 1
    " reads to the end of the input string, which contains a newline if you press return to enter it, which you probably do." That clears up a lot. I don't remember the author mentioning that pressing return after entering my input to will automatically contain a newline. Though that explains why a newline was being created even though I hadn't (knowingly) written one into the code. Thanks for your help. – krebshack Sep 03 '11 at 01:04
  • 1
    @kreb - this is not really Perl specific - the newline behavior is OS specific (and most OSs will do that, though different OSs have different newlines - that's where `$/` comes in. Windows/DOS newline is different from Unix newline. Lucky for you, Perl Just Works - namely, Windows Perl will set `$/` to Windows newline. See shawnhcorey's excellent answer below – DVK Sep 05 '11 at 17:42
3

OK, as of 1), perl doesn't add any \n at input. It is you that hit Enter when finished entering the number. If you don't specify $/, a default of \n will be put (under UNIX, at least).

As of 2), chomp will be needed whenever input comes from the user, or whenever you want to remove the line ending character (reading from a file, for example).

Finally, the error you're getting may be from perl not understanding your variable within the double quotes of the last print, because it does have a _ character. Try to write the string as follows:

print "$input can be reached at ${name_number{$input}}\n";

(note the {} around the last variable).

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
  • I'm not sure. I tried replacing my "print "$input ..." string with " with print ""$input can be reached at ${name_number{$input}}\n";" and it returned the same results when was followed by chomp. It also returned the same error message when wasn't followed by chomp. But, should writing strings the way you demonstrated be a habit that I should get into? – krebshack Sep 03 '11 at 01:15
  • Why the double *double* quotes? About the variables, yes, variables with special characters such as `_` should be surrounded by `{}` if within double quotes. – Diego Sevilla Sep 03 '11 at 01:17
  • Okay, that's good to know. I'll remove the double double quotes. It's a typo. – krebshack Sep 03 '11 at 01:20
  • There is no need for the outer `${}` construct in the hash - `$name_number{$input}` will interpolate just fine – Zaid Sep 03 '11 at 09:56
  • @Zaid, yes, maybe in this case, but when you have variables with underscores and nested access (hashes) it is better to do it out of better style. – Diego Sevilla Sep 03 '11 at 12:12
2

<STDIN> is a short-cut notation for readline( *STDIN );. What readline() does is reads the file handle until it encounters the contents of $/ (aka $INPUT_RECORD_SEPARATOR) and returns everything it has read including the contents of $/. What chomp() does is remove the last occurrence contents of $/, if present.

The contents is often called a newline character but it may be composed of more than one character. On Linux, it contains a LF character but on Windows, it contains CR-LF.

See:

perldoc -f readline
perldoc -f chomp
perldoc perlvar and search for /\$INPUT_RECORD_SEPARATOR/
shawnhcorey
  • 3,545
  • 1
  • 15
  • 17
0

I think best practice here is to write:

chomp(my $input = <STDIN>);

Here is quick example how chomp function ($/ meaning is explained there) works removing just one trailing new line (if any):

chomp (my $input = "Me\n"); # OK
chomp ($input = "Me"); # OK (nothing done)
chomp ($input = "Me\n\n"); # $input now is "Me\n";
chomp ($input); # finally "Me"

print "$input can be reached at $name_number{$input}\n"; 

BTW: That's funny thing is that I am learning Perl too and I reached hashes five minutes ago.

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • Oh, that is funny. What resources are you using? I find it's helpful to have access to as many tutorials/books/websites as I can when I'm learning something new. – krebshack Sep 03 '11 at 01:10
  • @krebshack: I am using mainly [Learning Perl](http://oreilly.com/catalog/0636920018452?green=c142e8ee-fefc-4f4d-80d1-fb6d1f20e787&cmp=af-mybuy-0636920018452.IP) (from [Safari Books](http://my.safaribooksonline.com/)) and sometimes [perldoc](http://perldoc.perl.org/). – Grzegorz Szpetkowski Sep 03 '11 at 01:15
  • I'll have to pick that up when my next paycheck comes in. I've had nothing but positive experiences with O'Reilly's. – krebshack Sep 03 '11 at 01:18
  • 1
    @kreb - many colleges and many workplaces would pay for your Safari subscription. Feel free to ask around in your school/work - won't hurt to try :) – DVK Sep 05 '11 at 17:44
0

Though it may be obvious, it's still worth mentioning why the chomp is needed here.

The hash created contains 4 lookup keys: "Me", "Home", "Emergency" and "Lookup"

When $input is specified from <STDIN>, it'll contain "Me\n", "Me\r\n" or some other line-ending variant depending on what operating system is being used.

The uninitialized value error comes about because the "Me\n" key does not exist in the hash. And this is why the chomp is needed:

my $input = <STDIN>; # "Me\n" --> Key DNE, $name_number{$input} not defined
chomp $input;        # "Me"   --> Key exists, $name_number{$input} defined
Zaid
  • 36,680
  • 16
  • 86
  • 155