perl

 view release on metacpan or  search on metacpan

cpan/perlfaq/lib/perlfaq4.pod  view on Meta::CPAN

     my ($d, $m, $y) = ( localtime $today-86400 )[3..5]; # WRONG
     printf "Yesterday: %d-%02d-%02d\n", $y+1900, $m+1, $d;

=head2 Does Perl have a Year 2000 or 2038 problem? Is Perl Y2K compliant?

(contributed by brian d foy)

Perl itself never had a Y2K problem, although that never stopped people
from creating Y2K problems on their own. See the documentation for
C<localtime> for its proper use.

Starting with Perl 5.12, C<localtime> and C<gmtime> can handle dates past
03:14:08 January 19, 2038, when a 32-bit based time would overflow. You
still might get a warning on a 32-bit C<perl>:

    % perl5.12 -E 'say scalar localtime( 0x9FFF_FFFFFFFF )'
    Integer overflow in hexadecimal number at -e line 1.
    Wed Nov  1 19:42:39 5576711

On a 64-bit C<perl>, you can get even larger dates for those really long
running projects:

    % perl5.12 -E 'say scalar gmtime( 0x9FFF_FFFFFFFF )'
    Thu Nov  2 00:42:39 5576711

You're still out of luck if you need to keep track of decaying protons
though.

=head1 Data: Strings

=head2 How do I validate input?

(contributed by brian d foy)

There are many ways to ensure that values are what you expect or
want to accept. Besides the specific examples that we cover in the
perlfaq, you can also look at the modules with "Assert" and "Validate"
in their names, along with other modules such as L<Regexp::Common>.

Some modules have validation for particular types of input, such
as L<Business::ISBN>, L<Business::CreditCard>, L<Email::Valid>,
and L<Data::Validate::IP>.

=head2 How do I unescape a string?

It depends just what you mean by "escape". URL escapes are dealt
with in L<perlfaq9>. Shell escapes with the backslash (C<\>)
character are removed with

    s/\\(.)/$1/g;

This won't expand C<"\n"> or C<"\t"> or any other special escapes.

=head2 How do I remove consecutive pairs of characters?

(contributed by brian d foy)

You can use the substitution operator to find pairs of characters (or
runs of characters) and replace them with a single instance. In this
substitution, we find a character in C<(.)>. The memory parentheses
store the matched character in the back-reference C<\g1> and we use
that to require that the same thing immediately follow it. We replace
that part of the string with the character in C<$1>.

    s/(.)\g1/$1/g;

We can also use the transliteration operator, C<tr///>. In this
example, the search list side of our C<tr///> contains nothing, but
the C<c> option complements that so it contains everything. The
replacement list also contains nothing, so the transliteration is
almost a no-op since it won't do any replacements (or more exactly,
replace the character with itself). However, the C<s> option squashes
duplicated and consecutive characters in the string so a character
does not show up next to itself

    my $str = 'Haarlem';   # in the Netherlands
    $str =~ tr///cs;       # Now Harlem, like in New York

=head2 How do I expand function calls in a string?

(contributed by brian d foy)

This is documented in L<perlref>, and although it's not the easiest
thing to read, it does work. In each of these examples, we call the
function inside the braces used to dereference a reference. If we
have more than one return value, we can construct and dereference an
anonymous array. In this case, we call the function in list context.

    print "The time values are @{ [localtime] }.\n";

If we want to call the function in scalar context, we have to do a bit
more work. We can really have any code we like inside the braces, so
we simply have to end with the scalar reference, although how you do
that is up to you, and you can use code inside the braces. Note that
the use of parens creates a list context, so we need C<scalar> to
force the scalar context on the function:

    print "The time is ${\(scalar localtime)}.\n"

    print "The time is ${ my $x = localtime; \$x }.\n";

If your function already returns a reference, you don't need to create
the reference yourself.

    sub timestamp { my $t = localtime; \$t }

    print "The time is ${ timestamp() }.\n";

The C<Interpolation> module can also do a lot of magic for you. You can
specify a variable name, in this case C<E>, to set up a tied hash that
does the interpolation for you. It has several other methods to do this
as well.

    use Interpolation E => 'eval';
    print "The time values are $E{localtime()}.\n";

In most cases, it is probably easier to simply use string concatenation,
which also forces scalar context.

    print "The time is " . localtime() . ".\n";

=head2 How do I find matching/nesting anything?

To find something between two single
characters, a pattern like C</x([^x]*)x/> will get the intervening

cpan/perlfaq/lib/perlfaq4.pod  view on Meta::CPAN

    }

You can also get into subtle problems on those few operations in Perl
that actually do care about the difference between a string and a
number, such as the magical C<++> autoincrement operator or the
syscall() function.

Stringification also destroys arrays.

    my @lines = `command`;
    print "@lines";     # WRONG - extra blanks
    print @lines;       # right

=head2 Why don't my E<lt>E<lt>HERE documents work?

Here documents are found in L<perlop>. Check for these three things:

=over 4

=item There must be no space after the E<lt>E<lt> part.

=item There (probably) should be a semicolon at the end of the opening token

=item You can't (easily) have any space in front of the tag.

=item There needs to be at least a line separator after the end token.

=back

If you want to indent the text in the here document, you
can do this:

    # all in one
    (my $VAR = <<HERE_TARGET) =~ s/^\s+//gm;
        your text
        goes here
    HERE_TARGET

But the HERE_TARGET must still be flush against the margin.
If you want that indented also, you'll have to quote
in the indentation.

    (my $quote = <<'    FINIS') =~ s/^\s+//gm;
            ...we will have peace, when you and all your works have
            perished--and the works of your dark master to whom you
            would deliver us. You are a liar, Saruman, and a corrupter
            of men's hearts. --Theoden in /usr/src/perl/taint.c
        FINIS
    $quote =~ s/\s+--/\n--/;

A nice general-purpose fixer-upper function for indented here documents
follows. It expects to be called with a here document as its argument.
It looks to see whether each line begins with a common substring, and
if so, strips that substring off. Otherwise, it takes the amount of leading
whitespace found on the first line and removes that much off each
subsequent line.

    sub fix {
        local $_ = shift;
        my ($white, $leader);  # common whitespace and common leading string
        if (/^\s*(?:([^\w\s]+)(\s*).*\n)(?:\s*\g1\g2?.*\n)+$/) {
            ($white, $leader) = ($2, quotemeta($1));
        } else {
            ($white, $leader) = (/^(\s+)/, '');
        }
        s/^\s*?$leader(?:$white)?//gm;
        return $_;
    }

This works with leading special strings, dynamically determined:

    my $remember_the_main = fix<<'    MAIN_INTERPRETER_LOOP';
    @@@ int
    @@@ runops() {
    @@@     SAVEI32(runlevel);
    @@@     runlevel++;
    @@@     while ( op = (*op->op_ppaddr)() );
    @@@     TAINT_NOT;
    @@@     return 0;
    @@@ }
    MAIN_INTERPRETER_LOOP

Or with a fixed amount of leading whitespace, with remaining
indentation correctly preserved:

    my $poem = fix<<EVER_ON_AND_ON;
       Now far ahead the Road has gone,
      And I must follow, if I can,
       Pursuing it with eager feet,
      Until it joins some larger way
       Where many paths and errands meet.
      And whither then? I cannot say.
        --Bilbo in /usr/src/perl/pp_ctl.c
    EVER_ON_AND_ON

Beginning with Perl version 5.26, a much simpler and cleaner way to
write indented here documents has been added to the language: the
tilde (~) modifier. See L<perlop/"Indented Here-docs"> for details.

=head1 Data: Arrays

=head2 What is the difference between a list and an array?

(contributed by brian d foy)

A list is a fixed collection of scalars. An array is a variable that
holds a variable collection of scalars. An array can supply its collection
for list operations, so list operations also work on arrays:

    # slices
    ( 'dog', 'cat', 'bird' )[2,3];
    @animals[2,3];

    # iteration
    foreach ( qw( dog cat bird ) ) { ... }
    foreach ( @animals ) { ... }

    my @three = grep { length == 3 } qw( dog cat bird );
    my @three = grep { length == 3 } @animals;

    # supply an argument list



( run in 0.234 second using v1.01-cache-2.11-cpan-4d50c553e7e )