The only thing I used that could be accused of being slightly obscure is:

do { local $/ = <$infile> }

This is a fairly commonly used idiom for reading an entire file into a single string, but exactly how it works is somewhat obscure.

Firstly, when you call <$filehandle>, Perl reads a single line from the file $filehandle. See perldoc -f readline

Secondly, the variable $/ is used by Perl's file reading function to indicate what character to use as a line terminator (technically it's called the record separator). So normally, $/ is set to "\n". If you set $/ to undef, then Perl won't treat any characters as line terminators, so the readline function will simply read the entire remainder of the file. See perldoc -f readline and perldoc perlvar

So, just based on the above knowledge, we can slurp the entire contents of a filehandle into a string like this:

$/ = undef; my $string = <$filehandle>;

But actually, what if other parts of our code rely on $/ being set to "\n"? We don't want to permanently undefine it.

my $old_terminator = $/; $/ = undef; my $string = <$filehandle>; $/ = $old_terminator;

Because temporarily changing the value of a variable is such a common need, Perl provides a shortcut. The local keyword allows you to set a new temporary value for a variable for a particular code block, such that the variable's old value will be automatically restored at the end of the block. See perldoc -f local. So our code becomes:

my $string; { local $/ = undef; $string = <$filehandle>; }

But = undef is redundant because all newly declared scalar variables (including local ones) are undefined. So now we have:

my $string; { local $/; $string = <$filehandle>; }

Now, the do block allows Perl to run a block of code and return the result of the last statement. See perlsyn. So our code can become:

my $string = do { local $/; <$filehandle>; }

The last simplification relies on the fact that in the following statement:

local $/ = <$filehandle>

Perl does things in this order:

  1. Localizes $/, setting it to undef.
  2. Reads the file - the entire file because $/ is undef.
  3. Performs the assignment.

Thus we end up with the situation where you can read the entire contents of an open file handle into a string using:

my $string = do { local $/ = <$infile> };

Now, of course I could have included the entire explanation above as a comment, but I try to stick to a policy of never writing comments which are longer than the code itself.


In reply to Re^3: putting text into array word by word by tobyink
in thread putting text into array word by word by jms53

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.