📄 perlfaq4.1
字号:
\& ($VAR = <<HERE_TARGET) =~ s/^\es+//gm;\& your text\& goes here\& HERE_TARGET.Ve.PPBut the \s-1HERE_TARGET\s0 must still be flush against the margin.If you want that indented also, you'll have to quotein the indentation..PP.Vb 7\& ($quote = <<\*(Aq FINIS\*(Aq) =~ s/^\es+//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\*(Aqs hearts. \-\-Theoden in /usr/src/perl/taint.c\& FINIS\& $quote =~ s/\es+\-\-/\en\-\-/;.Ve.PPA nice general-purpose fixer-upper function for indented here documentsfollows. It expects to be called with a here document as its argument.It looks to see whether each line begins with a common substring, andif so, strips that substring off. Otherwise, it takes the amount of leadingwhitespace found on the first line and removes that much off eachsubsequent line..PP.Vb 11\& sub fix {\& local $_ = shift;\& my ($white, $leader); # common whitespace and common leading string\& if (/^\es*(?:([^\ew\es]+)(\es*).*\en)(?:\es*\e1\e2?.*\en)+$/) {\& ($white, $leader) = ($2, quotemeta($1));\& } else {\& ($white, $leader) = (/^(\es+)/, \*(Aq\*(Aq);\& }\& s/^\es*?$leader(?:$white)?//gm;\& return $_;\& }.Ve.PPThis works with leading special strings, dynamically determined:.PP.Vb 10\& $remember_the_main = fix<<\*(Aq MAIN_INTERPRETER_LOOP\*(Aq;\& @@@ int\& @@@ runops() {\& @@@ SAVEI32(runlevel);\& @@@ runlevel++;\& @@@ while ( op = (*op\->op_ppaddr)() );\& @@@ TAINT_NOT;\& @@@ return 0;\& @@@ }\& MAIN_INTERPRETER_LOOP.Ve.PPOr with a fixed amount of leading whitespace, with remainingindentation correctly preserved:.PP.Vb 9\& $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.Ve.SH "Data: Arrays".IX Header "Data: Arrays".Sh "What is the difference between a list and an array?".IX Subsection "What is the difference between a list and an array?"An array has a changeable length. A list does not. An array issomething you can push or pop, while a list is a set of values. Somepeople make the distinction that a list is a value while an array is avariable. Subroutines are passed and return lists, you put things intolist context, you initialize arrays with lists, and you \f(CW\*(C`foreach()\*(C'\fRacross a list. \f(CW\*(C`@\*(C'\fR variables are arrays, anonymous arrays arearrays, arrays in scalar context behave like the number of elements inthem, subroutines access their arguments through the array \f(CW@_\fR, and\&\f(CW\*(C`push\*(C'\fR/\f(CW\*(C`pop\*(C'\fR/\f(CW\*(C`shift\*(C'\fR only work on arrays..PPAs a side note, there's no such thing as a list in scalar context.When you say.PP.Vb 1\& $scalar = (2, 5, 7, 9);.Ve.PPyou're using the comma operator in scalar context, so it uses the scalarcomma operator. There never was a list there at all! This causes thelast value to be returned: 9..ie n .Sh "What is the difference between $array\fP[1] and \f(CW@array[1]?".el .Sh "What is the difference between \f(CW$array\fP[1] and \f(CW@array\fP[1]?".IX Subsection "What is the difference between $array[1] and @array[1]?"The former is a scalar value; the latter an array slice, makingit a list with one (scalar) value. You should use $ when you want ascalar value (most of the time) and @ when you want a list with onescalar value in it (very, very rarely; nearly never, in fact)..PPSometimes it doesn't make a difference, but sometimes it does.For example, compare:.PP.Vb 1\& $good[0] = \`some program that outputs several lines\`;.Ve.PPwith.PP.Vb 1\& @bad[0] = \`same program that outputs several lines\`;.Ve.PPThe \f(CW\*(C`use warnings\*(C'\fR pragma and the \fB\-w\fR flag will warn you about thesematters..Sh "How can I remove duplicate elements from a list or array?".IX Subsection "How can I remove duplicate elements from a list or array?"(contributed by brian d foy).PPUse a hash. When you think the words \*(L"unique\*(R" or \*(L"duplicated\*(R", think\&\*(L"hash keys\*(R"..PPIf you don't care about the order of the elements, you could justcreate the hash then extract the keys. It's not important how youcreate that hash: just that you use \f(CW\*(C`keys\*(C'\fR to get the uniqueelements..PP.Vb 3\& my %hash = map { $_, 1 } @array;\& # or a hash slice: @hash{ @array } = ();\& # or a foreach: $hash{$_} = 1 foreach ( @array );\&\& my @unique = keys %hash;.Ve.PPIf you want to use a module, try the \f(CW\*(C`uniq\*(C'\fR function from\&\f(CW\*(C`List::MoreUtils\*(C'\fR. In list context it returns the unique elements,preserving their order in the list. In scalar context, it returns thenumber of unique elements..PP.Vb 1\& use List::MoreUtils qw(uniq);\&\& my @unique = uniq( 1, 2, 3, 4, 4, 5, 6, 5, 7 ); # 1,2,3,4,5,6,7\& my $unique = uniq( 1, 2, 3, 4, 4, 5, 6, 5, 7 ); # 7.Ve.PPYou can also go through each element and skip the ones you've seenbefore. Use a hash to keep track. The first time the loop sees anelement, that element has no key in \f(CW%Seen\fR. The \f(CW\*(C`next\*(C'\fR statementcreates the key and immediately uses its value, which is \f(CW\*(C`undef\*(C'\fR, sothe loop continues to the \f(CW\*(C`push\*(C'\fR and increments the value for thatkey. The next time the loop sees that same element, its key exists inthe hash \fIand\fR the value for that key is true (since it's not 0 or\&\f(CW\*(C`undef\*(C'\fR), so the next skips that iteration and the loop goes to thenext element..PP.Vb 2\& my @unique = ();\& my %seen = ();\&\& foreach my $elem ( @array )\& {\& next if $seen{ $elem }++;\& push @unique, $elem;\& }.Ve.PPYou can write this more briefly using a grep, which does thesame thing..PP.Vb 2\& my %seen = ();\& my @unique = grep { ! $seen{ $_ }++ } @array;.Ve.Sh "How can I tell whether a certain element is contained in a list or array?".IX Subsection "How can I tell whether a certain element is contained in a list or array?"(portions of this answer contributed by Anno Siegel).PPHearing the word \*(L"in\*(R" is an \fIin\fRdication that you probably should haveused a hash, not a list or array, to store your data. Hashes aredesigned to answer this question quickly and efficiently. Arrays aren't..PPThat being said, there are several ways to approach this. If youare going to make this query many times over arbitrary string values,the fastest way is probably to invert the original array and maintain ahash whose keys are the first array's values..PP.Vb 3\& @blues = qw/azure cerulean teal turquoise lapis\-lazuli/;\& %is_blue = ();\& for (@blues) { $is_blue{$_} = 1 }.Ve.PPNow you can check whether \f(CW$is_blue{$some_color}\fR. It might havebeen a good idea to keep the blues all in a hash in the first place..PPIf the values are all small integers, you could use a simple indexedarray. This kind of an array will take up less space:.PP.Vb 4\& @primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31);\& @is_tiny_prime = ();\& for (@primes) { $is_tiny_prime[$_] = 1 }\& # or simply @istiny_prime[@primes] = (1) x @primes;.Ve.PPNow you check whether \f(CW$is_tiny_prime\fR[$some_number]..PPIf the values in question are integers instead of strings, you can savequite a lot of space by using bit strings instead:.PP.Vb 3\& @articles = ( 1..10, 150..2000, 2017 );\& undef $read;\& for (@articles) { vec($read,$_,1) = 1 }.Ve.PPNow check whether \f(CW\*(C`vec($read,$n,1)\*(C'\fR is true for some \f(CW$n\fR..PPThese methods guarantee fast individual tests but require a re-organizationof the original list or array. They only pay off if you have to testmultiple values against the same array..PPIf you are testing only once, the standard module \f(CW\*(C`List::Util\*(C'\fR exportsthe function \f(CW\*(C`first\*(C'\fR for this purpose. It works by stopping once itfinds the element. It's written in C for speed, and its Perl equivalentlooks like this subroutine:.PP.Vb 7\& sub first (&@) {\& my $code = shift;\& foreach (@_) {\& return $_ if &{$code}();\& }\& undef;\& }.Ve.PPIf speed is of little concern, the common idiom uses grep in scalar context(which returns the number of items that passed its condition) to traverse theentire list. This does have the benefit of telling you how many matches itfound, though..PP.Vb 1\& my $is_there = grep $_ eq $whatever, @array;.Ve.PPIf you want to actually extract the matching elements, simply use grep inlist context..PP.Vb 1\& my @matches = grep $_ eq $whatever, @array;.Ve.Sh "How do I compute the difference of two arrays? How do I compute the intersection of two arrays?".IX Subsection "How do I compute the difference of two arrays? How do I compute the intersection of two arrays?"Use a hash. Here's code to do both and more. It assumes that eachelement is unique in a given array:.PP.Vb 7\& @union = @intersection = @difference = ();\& %count = ();\& foreach $element (@array1, @array2) { $count{$element}++ }\& foreach $element (keys %count) {\& push @union, $element;\& push @{ $count{$element} > 1 ? \e@intersection : \e@difference }, $element;\& }.Ve.PPNote that this is the \fIsymmetric difference\fR, that is, all elementsin either A or in B but not in both. Think of it as an xor operation..Sh "How do I test whether two arrays or hashes are equal?".IX Subsection "How do I test whether two arrays or hashes are equal?"The following code works for single-level arrays. It uses astringwise comparison, and does not distinguish defined versusundefined empty strings. Modify if you have other needs..PP.Vb 1\& $are_equal = compare_arrays(\e@frogs, \e@toads);\&\& sub compare_arrays {\& my ($first, $second) = @_;\& no warnings; # silence spurious \-w undef complaints\& return 0 unless @$first == @$second;\& for (my $i = 0; $i < @$first; $i++) {\& return 0 if $first\->[$i] ne $second\->[$i];\& }\& return 1;\& }.Ve.PPFor multilevel structures, you may wish to use an approach morelike this one. It uses the \s-1CPAN\s0 module \f(CW\*(C`FreezeThaw\*(C'\fR:.PP.Vb 2\& use FreezeThaw qw(cmpStr);\& @a = @b = ( "this", "that", [ "more", "stuff" ] );\&\& printf "a and b contain %s arrays\en",\& cmpStr(\e@a, \e@b) == 0\& ? "the same"\& : "different";.Ve.PPThis approach also works for comparing hashes. Here we'll demonstratetwo different answers:.PP.Vb 1\& use FreezeThaw qw(cmpStr cmpStrHard);\&\& %a = %b = ( "this" => "that", "extra" => [ "more", "stuff" ] );\& $a{EXTRA} = \e%b;\& $b{EXTRA} = \e%a;\&\& printf "a and b contain %s hashes\en",\& cmpStr(\e%a, \e%b) == 0 ? "the same" : "different";\&\& printf "a and b contain %s hashes\en",\& cmpStrHard(\e%a, \e%b) == 0 ? "the same" : "different";.Ve.PPThe first reports that both those the hashes contain the same data,while the second reports that they do not. Which you prefer is left asan exercise to the reader..Sh "How do I find the first array element for which a condition is true?".IX Subsection "How do I find the first array element for which a condition is true?"To find the first array element which satisfies a condition, you canuse the \f(CW\*(C`first()\*(C'\fR function in the \f(CW\*(C`List::Util\*(C'\fR module, which comeswith Perl 5.8. This example finds the first element that contains\&\*(L"Perl\*(R"..PP.Vb 1\& use List::Util qw(first);\&\& my $element = first { /Perl/ } @array;.Ve.PPIf you cannot use \f(CW\*(C`List::Util\*(C'\fR, you can make your own loop to do thesame thing. Once you find the element, you stop the loop with last..PP.Vb 4\& my $found;\& foreach ( @array ) {\& if( /Perl/ ) { $found = $_; last }\& }.Ve.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -