From 6670e5e7b286c73a0b574b82775e6e4a452e6dcc Mon Sep 17 00:00:00 2001 From: Rafael Garcia-Suarez Date: Fri, 3 Jun 2005 07:58:10 +0000 Subject: [PATCH] FAQ sync p4raw-id: //depot/perl@24684 --- pod/perlfaq1.pod | 2 +- pod/perlfaq2.pod | 14 +-- pod/perlfaq3.pod | 10 +- pod/perlfaq4.pod | 322 ++++++++++++++++++++++++++++++------------------------- pod/perlfaq5.pod | 4 +- pod/perlfaq6.pod | 30 +++--- pod/perlfaq7.pod | 88 +++++++++------ pod/perlfaq8.pod | 20 ++-- pod/perlfaq9.pod | 19 ++-- 9 files changed, 277 insertions(+), 232 deletions(-) diff --git a/pod/perlfaq1.pod b/pod/perlfaq1.pod index 0e15587..dacc2f2 100644 --- a/pod/perlfaq1.pod +++ b/pod/perlfaq1.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq1 - General Questions About Perl ($Revision: 1.17 $, $Date: 2005/01/31 15:52:15 $) +perlfaq1 - General Questions About Perl ($Revision: 1.18 $, $Date: 2005/04/01 16:15:25 $) =head1 DESCRIPTION diff --git a/pod/perlfaq2.pod b/pod/perlfaq2.pod index a0fdf30..9d2443a 100644 --- a/pod/perlfaq2.pod +++ b/pod/perlfaq2.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq2 - Obtaining and Learning about Perl ($Revision: 1.31 $, $Date: 2005/01/31 15:54:44 $) +perlfaq2 - Obtaining and Learning about Perl ($Revision: 1.32 $, $Date: 2005/04/22 19:04:48 $) =head1 DESCRIPTION @@ -195,7 +195,7 @@ under the C hierarchy at http://groups.google.com . Other groups are listed at http://lists.perl.org/ ( also known as http://lists.cpan.org/ ). -A nice place to ask questions is the PerlMonks site, +A nice place to ask questions is the PerlMonks site, http://www.perlmonks.org/ , or the Perl Beginners mailing list http://lists.perl.org/showlist.cgi?name=beginners . @@ -219,7 +219,7 @@ This is faster and more productive than just posting a request. =head2 Perl Books A number of books on Perl and/or CGI programming are available. A few -of these are good, some are OK, but many aren't worth your money. +of these are good, some are OK, but many aren't worth your money. There is a list of these books, some with extensive reviews, at http://books.perl.org/ . @@ -385,7 +385,7 @@ Recommended books on (or mostly on) Perl follow. by Scott Walters ISBN 1-59059-395-2 [1st edition December 2004 http://apress.com/book/bookDisplay.html?bID=355 - + Mastering Regular Expressions by Jeffrey E. F. Friedl ISBN 0-596-00289-0 [2nd edition July 2002] @@ -420,7 +420,7 @@ Recommended books on (or mostly on) Perl follow. Perl Debugger Pocket Reference by Richard Foley ISBN 0-596-00503-2 [1st edition January 2004] - http://www.oreilly.com/catalog/perldebugpr/ + http://www.oreilly.com/catalog/perldebugpr/ =back @@ -431,8 +431,8 @@ I contains tutorials, demonstrations, case studies, announcements, contests, and much more. I has columns on web development, databases, Win32 Perl, graphical programming, regular expressions, and networking, and sponsors the Obfuscated Perl Contest -and the Perl Poetry Contests. Beginning in November 2002, TPJ moved to a -reader-supported monthly e-zine format in which subscribers can download +and the Perl Poetry Contests. Beginning in November 2002, TPJ moved to a +reader-supported monthly e-zine format in which subscribers can download issues as PDF documents. For more details on TPJ, see http://www.tpj.com/ Beyond this, magazines that frequently carry quality articles on diff --git a/pod/perlfaq3.pod b/pod/perlfaq3.pod index b166f32..032fc67 100644 --- a/pod/perlfaq3.pod +++ b/pod/perlfaq3.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq3 - Programming Tools ($Revision: 1.47 $, $Date: 2005/03/27 07:21:22 $) +perlfaq3 - Programming Tools ($Revision: 1.48 $, $Date: 2005/04/22 19:04:48 $) =head1 DESCRIPTION @@ -225,7 +225,7 @@ order of preference): =item Eclipse -The Eclipse Perl Integration Project integrates Perl +The Eclipse Perl Integration Project integrates Perl editing/debugging with Eclipse. The website for the project is http://e-p-i-c.sf.net/ @@ -407,7 +407,7 @@ no 32k limit). =item Affrus -is a full Perl development enivornment with full debugger support +is a full Perl development enivornment with full debugger support ( http://www.latenightsw.com ). =item Alpha @@ -754,10 +754,10 @@ you want to be sure your license's wording will stand up in court. In general, you can't do this. There are some things that may work for your situation though. People usually ask this question -because they want to distribute their works without giving away +because they want to distribute their works without giving away the source code, and most solutions trade disk space for convenience. You probably won't see much of a speed increase either, since most -solutions simply bundle a Perl interpreter in the final product +solutions simply bundle a Perl interpreter in the final product (but see L). The Perl Archive Toolkit (http://par.perl.org/index.cgi) is diff --git a/pod/perlfaq4.pod b/pod/perlfaq4.pod index de7feee..67ab210 100644 --- a/pod/perlfaq4.pod +++ b/pod/perlfaq4.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq4 - Data Manipulation ($Revision: 1.61 $, $Date: 2005/03/11 16:27:53 $) +perlfaq4 - Data Manipulation ($Revision: 1.64 $, $Date: 2005/04/27 00:18:04 $) =head1 DESCRIPTION @@ -406,7 +406,7 @@ a time in epoch seconds for the argument to localtime. use POSIX qw/strftime/; use Time::Local; - my $week_of_year = strftime "%W", + my $week_of_year = strftime "%W", localtime( timelocal( 0, 0, 0, 18, 11, 1987 ) ); The Date::Calc module provides two functions for to calculate these. @@ -422,7 +422,7 @@ Use the following simple functions: sub get_century { return int((((localtime(shift || time))[5] + 1999))/100); } - + sub get_millennium { return 1+int((((localtime(shift || time))[5] + 1899))/1000); } @@ -481,60 +481,30 @@ Julian day) =head2 How do I find yesterday's date? -If you only need to find the date (and not the same time), you -can use the Date::Calc module. - - use Date::Calc qw(Today Add_Delta_Days); - - my @date = Add_Delta_Days( Today(), -1 ); - - print "@date\n"; - -Most people try to use the time rather than the calendar to -figure out dates, but that assumes that your days are -twenty-four hours each. For most people, there are two days -a year when they aren't: the switch to and from summer time -throws this off. Russ Allbery offers this solution. - - sub yesterday { - my $now = defined $_[0] ? $_[0] : time; - my $then = $now - 60 * 60 * 24; - my $ndst = (localtime $now)[8] > 0; - my $tdst = (localtime $then)[8] > 0; - $then - ($tdst - $ndst) * 60 * 60; - } - -Should give you "this time yesterday" in seconds since epoch relative to -the first argument or the current time if no argument is given and -suitable for passing to localtime or whatever else you need to do with -it. $ndst is whether we're currently in daylight savings time; $tdst is -whether the point 24 hours ago was in daylight savings time. If $tdst -and $ndst are the same, a boundary wasn't crossed, and the correction -will subtract 0. If $tdst is 1 and $ndst is 0, subtract an hour more -from yesterday's time since we gained an extra hour while going off -daylight savings time. If $tdst is 0 and $ndst is 1, subtract a -negative hour (add an hour) to yesterday's time since we lost an hour. - -All of this is because during those days when one switches off or onto -DST, a "day" isn't 24 hours long; it's either 23 or 25. - -The explicit settings of $ndst and $tdst are necessary because localtime -only says it returns the system tm struct, and the system tm struct at -least on Solaris doesn't guarantee any particular positive value (like, -say, 1) for isdst, just a positive value. And that value can -potentially be negative, if DST information isn't available (this sub -just treats those cases like no DST). +(contributed by brian d foy) -Note that between 2am and 3am on the day after the time zone switches -off daylight savings time, the exact hour of "yesterday" corresponding -to the current hour is not clearly defined. Note also that if used -between 2am and 3am the day after the change to daylight savings time, -the result will be between 3am and 4am of the previous day; it's -arguable whether this is correct. +Use one of the Date modules. The C module makes it simple, and +give you the same time of day, only the day before. -This sub does not attempt to deal with leap seconds (most things don't). + use DateTime; + + my $yesterday = DateTime->now->subtract( days => 1 ); + + print "Yesterday was $yesterday\n"; +You can also use the C module using its Today_and_Now +function. + use Date::Calc qw( Today_and_Now Add_Delta_DHMS ); + + my @date_time = Add_Delta_DHMS( Today_and_Now(), -1, 0, 0, 0 ); + + print "@date\n"; + +Most people try to use the time rather than the calendar to figure out +dates, but that assumes that days are twenty-four hours each. For +most people, there are two days a year when they aren't: the switch to +and from summer time throws this off. Let the modules do the work. =head2 Does Perl have a Year 2000 problem? Is Perl Y2K compliant? @@ -570,9 +540,16 @@ a longer exposition. =head2 How do I validate input? -The answer to this question is usually a regular expression, perhaps -with auxiliary logic. See the more specific questions (numbers, mail -addresses, etc.) for details. +(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 C. + +Some modules have validation for particular types of input, such +as C, C, C, +and C. =head2 How do I unescape a string? @@ -586,21 +563,61 @@ This won't expand C<"\n"> or C<"\t"> or any other special escapes. =head2 How do I remove consecutive pairs of characters? -To turn C<"abbcccd"> into C<"abccd">: +(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<\1> 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/(.)\1/$1/g; # add /s to include newlines + s/(.)\1/$1/g; -Here's a solution that turns "abbcccd" to "abcd": +We can also use the transliteration operator, C. In this +example, the search list side of our C contains nothing, but +the 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 option squashes +duplicated and consecutive characters in the string so a character +does not show up next to itself - y///cs; # y == tr, but shorter :-) + 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? -This is documented in L. In general, this is fraught with -quoting and readability problems, but it is possible. To interpolate -a subroutine call (in list context) into a string: +(contributed by brian d foy) + +This is documented in L, 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 of used to dereference a reference. If we +have a more than one return value, we can contruct 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. - print "My sub returned @{[mysub(1,2,3)]} that time.\n"; + 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"; + +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? @@ -609,15 +626,16 @@ matter how complicated. To find something between two single characters, a pattern like C will get the intervening bits in $1. For multiple ones, then something more like C would be needed. But none of these deals with -nested patterns. For balanced expressions using C<(>, C<{>, C<[> -or C<< < >> as delimiters, use the CPAN module Regexp::Common, or see -L. For other cases, you'll have to write a parser. +nested patterns. For balanced expressions using C<(>, C<{>, C<[> or +C<< < >> as delimiters, use the CPAN module Regexp::Common, or see +L. For other cases, you'll have to write a +parser. If you are serious about writing a parser, there are a number of modules or oddities that will make your life a lot easier. There are the CPAN modules Parse::RecDescent, Parse::Yapp, and Text::Balanced; -and the byacc program. Starting from perl 5.8 the Text::Balanced -is part of the standard distribution. +and the byacc program. Starting from perl 5.8 the Text::Balanced is +part of the standard distribution. One simple destructive, inside-out approach that you might try is to pull out the smallest nesting parts one at a time: @@ -841,34 +859,52 @@ There's also a Text::CSV (Comma-Separated Values) module on CPAN. =head2 How do I strip blank space from the beginning/end of a string? -Although the simplest approach would seem to be +(contributed by brian d foy) - $string =~ s/^\s*(.*?)\s*$/$1/; +A substitution can do this for you. For a single line, you want to +replace all the leading or trailing whitespace with nothing. You +can do that with a pair of substitutions. -not only is this unnecessarily slow and destructive, it also fails with -embedded newlines. It is much faster to do this operation in two steps: + s/^\s+//; + s/\s+$//; - $string =~ s/^\s+//; - $string =~ s/\s+$//; +You can also write that as a single substitution, although it turns +out the combined statement is slower than the separate ones. That +might not matter to you, though. -Or more nicely written as: + s/^\s+|\s+$//g; - for ($string) { - s/^\s+//; - s/\s+$//; - } +In this regular expression, the alternation matches either at the +beginning or the end of the string since the anchors have a lower +precedence than the alternation. With the C flag, the substitution +makes all possible matches, so it gets both. Remember, the trailing +newline matches the C<\s+>, and the C<$> anchor can match to the +physical end of the string, so the newline disappears too. Just add +the newline to the output, which has the added benefit of preserving +"blank" (consisting entirely of whitespace) lines which the C<^\s+> +would remove all by itself. -This idiom takes advantage of the C loop's aliasing -behavior to factor out common code. You can do this -on several strings at once, or arrays, or even the -values of a hash if you use a slice: + while( <> ) + { + s/^\s+|\s+$//g; + print "$_\n"; + } - # trim whitespace in the scalar, the array, - # and all the values in the hash - foreach ($scalar, @array, @hash{keys %hash}) { - s/^\s+//; - s/\s+$//; - } +For a multi-line string, you can apply the regular expression +to each logical line in the string by adding the C flag (for +"multi-line"). With the C flag, the C<$> matches I an +embedded newline, so it doesn't remove it. It still removes the +newline at the end of the string. + + $string =~ s/^\s+|\s+$//gm; + +Remember that lines consisting entirely of whitespace will disappear, +since the first part of the alternation can match the entire string +and replace it with nothing. If need to keep embedded blank lines, +you have to do a little more work. Instead of matching any whitespace +(since that includes a newline), just match the other whitespace. + + $string =~ s/^[\t\f ]+|[\t\f ]+$//mg; =head2 How do I pad a string with blanks or pad a number with zeroes? @@ -1136,56 +1172,46 @@ matters. =head2 How can I remove duplicate elements from a list or array? -There are several possible ways, depending on whether the array is -ordered and whether you wish to preserve the ordering. - -=over 4 - -=item a) - -If @in is sorted, and you want @out to be sorted: -(this assumes all true values in the array) - - $prev = "not equal to $in[0]"; - @out = grep($_ ne $prev && ($prev = $_, 1), @in); - -This is nice in that it doesn't use much extra memory, simulating -uniq(1)'s behavior of removing only adjacent duplicates. The ", 1" -guarantees that the expression is true (so that grep picks it up) -even if the $_ is 0, "", or undef. - -=item b) - -If you don't know whether @in is sorted: - - undef %saw; - @out = grep(!$saw{$_}++, @in); - -=item c) - -Like (b), but @in contains only small integers: +(contributed by brian d foy) - @out = grep(!$saw[$_]++, @in); +Use a hash. When you think the words "unique" or "duplicated", think +"hash keys". -=item d) +If you don't care about the order of the elements, you could just +create the hash then extract the keys. It's not important how you +create that hash: just that you use C to get the unique +elements. -A way to do (b) without any loops or greps: + my %hash = map { $_, 1 } @array; + # or a hash slice: @hash{ @array } = (); + # or a foreach: $hash{$_} = 1 foreach ( @array ); - undef %saw; - @saw{@in} = (); - @out = sort keys %saw; # remove sort if undesired + my @unique = keys %hash; -=item e) +You can also go through each element and skip the ones you've seen +before. Use a hash to keep track. The first time the loop sees an +element, that element has no key in C<%Seen>. The C statement +creates the key and immediately uses its value, which is C, so +the loop continues to the C and increments the value for that +key. The next time the loop sees that same element, its key exists in +the hash I the value for that key is true (since it's not 0 or +undef), so the next skips that iteration and the loop goes to the next +element. -Like (d), but @in contains only small positive integers: + my @unique = (); + my %seen = (); - undef @ary; - @ary[@in] = @in; - @out = grep {defined} @ary; + foreach my $elem ( @array ) + { + next if $seen{ $elem }++; + push @unique, $elem; + } -=back +You can write this more briefly using a grep, which does the +same thing. -But perhaps you should have been using a hash all along, eh? + my %seen = (); + my @unique = grep { ! $seen{ $_ }++ } @array; =head2 How can I tell whether a certain element is contained in a list or array? @@ -1325,9 +1351,9 @@ If you cannot use List::Util, you can make your own loop to do the same thing. Once you find the element, you stop the loop with last. my $found; - foreach my $element ( @array ) + foreach ( @array ) { - if( /Perl/ ) { $found = $element; last } + if( /Perl/ ) { $found = $_; last } } If you want the array index, you can iterate through the indices @@ -1335,15 +1361,15 @@ and check the array element at each index until you find one that satisfies the condition. my( $found, $index ) = ( undef, -1 ); - for( $i = 0; $i < @array; $i++ ) - { - if( $array[$i] =~ /Perl/ ) - { - $found = $array[$i]; - $index = $i; - last; - } - } + for( $i = 0; $i < @array; $i++ ) + { + if( $array[$i] =~ /Perl/ ) + { + $found = $array[$i]; + $index = $i; + last; + } + } =head2 How do I handle linked lists? @@ -1416,7 +1442,7 @@ If not, you can use a Fisher-Yates shuffle. sub fisher_yates_shuffle { my $deck = shift; # $deck is a reference to an array my $i = @$deck; - while ($i--) { + while (--$i) { my $j = int rand ($i+1); @$deck[$i,$j] = @$deck[$j,$i]; } @@ -1452,15 +1478,15 @@ this until you have rather largish arrays. Use C/C: for (@lines) { - s/foo/bar/; # change that word - y/XZ/ZX/; # swap those letters + s/foo/bar/; # change that word + tr/XZ/ZX/; # swap those letters } Here's another; let's compute spherical volumes: for (@volumes = @radii) { # @volumes has changed parts - $_ **= 3; - $_ *= (4/3) * 3.14159; # this will be constant folded + $_ **= 3; + $_ *= (4/3) * 3.14159; # this will be constant folded } which can also be done with map() which is made to transform @@ -1474,7 +1500,7 @@ the values are not copied, so if you modify $orbit (in this case), you modify the value. for $orbit ( values %orbits ) { - ($orbit **= 3) *= (4/3) * 3.14159; + ($orbit **= 3) *= (4/3) * 3.14159; } Prior to perl 5.6 C returned copies of the values, diff --git a/pod/perlfaq5.pod b/pod/perlfaq5.pod index ab0ba26..45a1aa8 100644 --- a/pod/perlfaq5.pod +++ b/pod/perlfaq5.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq5 - Files and Formats ($Revision: 1.35 $, $Date: 2005/01/21 12:26:11 $) +perlfaq5 - Files and Formats ($Revision: 1.36 $, $Date: 2005/04/22 19:04:48 $) =head1 DESCRIPTION @@ -129,7 +129,7 @@ with C in place of the file name. The C function creates an anonymous temporary file. open my $tmp, '+>', undef or die $!; - + Otherwise, you can use the File::Temp module. use File::Temp qw/ tempfile tempdir /; diff --git a/pod/perlfaq6.pod b/pod/perlfaq6.pod index 406712b..840f5de 100644 --- a/pod/perlfaq6.pod +++ b/pod/perlfaq6.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq6 - Regular Expressions ($Revision: 1.31 $, $Date: 2005/03/27 07:17:28 $) +perlfaq6 - Regular Expressions ($Revision: 1.32 $, $Date: 2005/04/22 19:04:48 $) =head1 DESCRIPTION @@ -520,16 +520,16 @@ See the module String::Approx available from CPAN. ( contributed by brian d foy ) -Avoid asking Perl to compile a regular expression every time +Avoid asking Perl to compile a regular expression every time you want to match it. In this example, perl must recompile the regular expression for every iteration of the foreach() loop since it has no way to know what $pattern will be. @patterns = qw( foo bar baz ); - - LINE: while( <> ) + + LINE: while( <> ) { - foreach $pattern ( @patterns ) + foreach $pattern ( @patterns ) { print if /\b$pattern\b/i; next LINE; @@ -545,22 +545,22 @@ but faster. @patterns = map { qr/\b$_\b/i } qw( foo bar baz ); - LINE: while( <> ) + LINE: while( <> ) { - foreach $pattern ( @patterns ) + foreach $pattern ( @patterns ) { print if /\b$pattern\b/i; next LINE; } } - + In some cases, you may be able to make several patterns into a single regular expression. Beware of situations that require backtracking though. $regex = join '|', qw( foo bar baz ); - LINE: while( <> ) + LINE: while( <> ) { print if /\b(?:$regex)\b/i; } @@ -568,7 +568,7 @@ backtracking though. For more details on regular expression efficiency, see Mastering Regular Expressions by Jeffrey Freidl. He explains how regular expressions engine work and why some patterns are surprisingly -inefficient. Once you understand how perl applies regular +inefficient. Once you understand how perl applies regular expressions, you can tune them for individual situations. =head2 Why don't word-boundary searches with C<\b> work for me? @@ -601,18 +601,18 @@ These strings do not match /\bPerl\b/. "Perl_" # _ is a word char! "Perler" # no word char before P, but one after l - + You don't have to use \b to match words though. You can look for non-word characters surrrounded by word characters. These strings match the pattern /\b'\b/. "don't" # the ' char is surrounded by "n" and "t" "qep'a'" # the ' char is surrounded by "p" and "a" - + These strings do not match /\b'\b/. "foo'" # there is no word char after non-word ' - + You can also use the complement of \b, \B, to specify that there should not be a word boundary. @@ -621,7 +621,7 @@ and after the "m". These patterns match /\Bam\B/: "llama" # "am" surrounded by word chars "Samuel" # same - + These strings do not match /\Bam\B/ "Sam" # no word boundary before "a", but one after "m" @@ -641,7 +641,7 @@ if you can, but if you can't, once you've used them at all, use them at will because you've already paid the price. Remember that some algorithms really appreciate them. As of the 5.005 release, the $& variable is no longer "expensive" the way the other two are. - + =head2 What good is C<\G> in a regular expression? You use the C<\G> anchor to start the next match on the same diff --git a/pod/perlfaq7.pod b/pod/perlfaq7.pod index b87f096..ac9b31f 100644 --- a/pod/perlfaq7.pod +++ b/pod/perlfaq7.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq7 - General Perl Language Issues ($Revision: 1.22 $, $Date: 2005/03/27 07:19:01 $) +perlfaq7 - General Perl Language Issues ($Revision: 1.23 $, $Date: 2005/04/07 21:39:34 $) =head1 DESCRIPTION @@ -97,7 +97,7 @@ See L for more details. no warnings; # temporarily turn off warnings $a = $b + $c; # I know these might be undef } - + Additionally, you can enable and disable categories of warnings. You turn off the categories you want to ignore and you can still get other categories of warnings. See L for the @@ -411,42 +411,62 @@ You could also investigate the can() method in the UNIVERSAL class =head2 How do I create a static variable? -As with most things in Perl, TMTOWTDI. What is a "static variable" in -other languages could be either a function-private variable (visible -only within a single function, retaining its value between calls to -that function), or a file-private variable (visible only to functions -within the file it was declared in) in Perl. +(contributed by brian d foy) -Here's code to implement a function-private variable: +Perl doesn't have "static" variables, which can only be accessed from +the function in which they are declared. You can get the same effect +with lexical variables, though. + +You can fake a static variable by using a lexical variable which goes +of scope. In this example, you define the subroutine C, and +it uses the lexical variable C<$count>. Since you wrap this in a BEGIN +block, C<$count> is defined at compile-time, but also goes out of +scope at the end of the BEGIN block. The BEGIN block also ensures that +the subroutine and the value it uses is defined at compile-time so the +subroutine is ready to use just like any other subroutine, and you can +put this code in the same place as other subroutines in the program +text (i.e. at the end of the code, typically). The subroutine +C still has a reference to the data, and is the only way you +can access the value (and each time you do, you increment the value). +The data in chunk of memory defined by C<$count> is private to +C. + + BEGIN { + my $count = 1; + sub counter { $count++ } + } - BEGIN { - my $counter = 42; - sub prev_counter { return --$counter } - sub next_counter { return $counter++ } - } + my $start = count(); -Now prev_counter() and next_counter() share a private variable $counter -that was initialized at compile time. + .... # code that calls count(); -To declare a file-private variable, you'll still use a my(), putting -the declaration at the outer scope level at the top of the file. -Assume this is in file Pax.pm: + my $end = count(); - package Pax; - my $started = scalar(localtime(time())); +In the previous example, you created a function-private variable +because only one function remembered its reference. You could define +multiple functions while the variable is in scope, and each function +can share the "private" variable. It's not really "static" because you +can access it outside the function while the lexical variable is in +scope, and even create references to it. In this example, +C and C share the variable. One +function adds to the value and the other simply returns the value. +They can both access C<$count>, and since it has gone out of scope, +there is no other way to access it. - sub begun { return $started } + BEGIN { + my $count = 1; + sub increment_count { $count++ } + sub return_count { $count } + } -When C or C loads this module, the variable will -be initialized. It won't get garbage-collected the way most variables -going out of scope do, because the begun() function cares about it, -but no one else can get it. It is not called $Pax::started because -its scope is unrelated to the package. It's scoped to the file. You -could conceivably have several packages in that same file all -accessing the same private variable, but another file with the same -package couldn't get to it. +To declare a file-private variable, you still use a lexical variable. +A file is also a scope, so a lexical variable defined in the file +cannot be seen from any other file. -See L for details. +See L for more information. +The discussion of closures in L may help you even though we +did not use anonymous subroutines in this answer. See +L for details. =head2 What's the difference between dynamic and lexical (static) scoping? Between local() and my()? @@ -757,7 +777,7 @@ with <=end>. by everyone =end comment - + =cut # program continues @@ -904,12 +924,12 @@ settings. If you see "bad interpreter - no such file or directory", the first line in your perl script (the "shebang" line) does not contain the -right path to perl (or any other program capable of running scripts). +right path to perl (or any other program capable of running scripts). Sometimes this happens when you move the script from one machine to another and each machine has a different path to perl---/usr/bin/perl versus /usr/local/bin/perl for instance. It may also indicate -that the source machine has CRLF line terminators and the -destination machine has LF only: the shell tries to find +that the source machine has CRLF line terminators and the +destination machine has LF only: the shell tries to find /usr/bin/perl, but can't. If you see "bad interpreter: Permission denied", you need to make your diff --git a/pod/perlfaq8.pod b/pod/perlfaq8.pod index 8152d49..9648bff 100644 --- a/pod/perlfaq8.pod +++ b/pod/perlfaq8.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq8 - System Interaction ($Revision: 1.23 $, $Date: 2005/01/03 18:43:37 $) +perlfaq8 - System Interaction ($Revision: 1.24 $, $Date: 2005/04/22 19:04:48 $) =head1 DESCRIPTION @@ -413,22 +413,22 @@ foregrounded process group, which you then trap in your process. Signals are documented in L and the section on ``Signals'' in the Camel. -You can set the values of the %SIG hash to be the functions you want +You can set the values of the %SIG hash to be the functions you want to handle the signal. After perl catches the signal, it looks in %SIG for a key with the same name as the signal, then calls the subroutine value for that key. # as an anonymous subroutine - + $SIG{INT} = sub { syswrite(STDERR, "ouch\n", 5 ) }; - + # or a reference to a function - + $SIG{INT} = \&ouch; - + # or the name of the function as a string - - $SIG{INT} = "ouch"; + + $SIG{INT} = "ouch"; Perl versions before 5.8 had in its C source code signal handlers which would catch the signal and possibly run a Perl function that you had set @@ -1095,12 +1095,12 @@ A quick and dirty fix involves a little bit of code, but this may be all you need to figure out the problem. #!/usr/bin/perl -w - + BEGIN { $SIG{__WARN__} = sub{ print STDERR "Perl: ", @_; }; $SIG{__DIE__} = sub{ print STDERR "Perl: ", @_; exit 1}; } - + $a = 1 + undef; $x / 0; __END__ diff --git a/pod/perlfaq9.pod b/pod/perlfaq9.pod index 0dd6f1e..1a40c3b 100644 --- a/pod/perlfaq9.pod +++ b/pod/perlfaq9.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq9 - Networking ($Revision: 1.19 $, $Date: 2005/01/21 12:14:12 $) +perlfaq9 - Networking ($Revision: 1.21 $, $Date: 2005/04/22 19:04:48 $) =head1 DESCRIPTION @@ -16,9 +16,8 @@ a program ("CGI script") and a web server (HTTPD). It is not specific to Perl, and has its own FAQs and tutorials, and usenet group, comp.infosystems.www.authoring.cgi -The original CGI specification is at: http://hoohoo.ncsa.uiuc.edu/cgi/ - -Current best-practice RFC draft at: http://CGI-Spec.Golux.Com/ +The CGI specification is outlined in an informational RFC: +http://www.ietf.org/rfc/rfc3875 Other relevant documentation listed in: http://www.perl.org/CGI_MetaFAQ.html @@ -366,19 +365,19 @@ parses the input and makes each value available through the C function. use CGI qw(:standard); - + my $total = param( "price" ) + param( "shipping" ); - + my @items = param( "item ); # multiple values, same field name - + If you want an object-oriented approach, CGI.pm can do that too. use CGI; - + my $cgi = CGI->new(); - + my $total = $cgi->param( "price" ) + $cgi->param( "shipping" ); - + my @items = $cgi->param( "item" ); You might also try CGI::Minimal which is a lightweight version -- 1.8.3.1