📄 ch01_06.htm
字号:
<tt class="literal">until</tt>, <tt class="literal">for</tt>, and<tt class="literal">foreach</tt>. These statements allow a Perl program torepeatedly execute the same code.</p><h3 class="sect3">1.6.2.1. The while and until statements</h3><p><a name="INDEX-305"></a><a name="INDEX-306"></a><a name="INDEX-307"></a><a name="INDEX-308"></a> The <tt class="literal">while</tt> and<tt class="literal">until</tt> statements behave just like the<tt class="literal">if</tt> and <tt class="literal">unless</tt> statements, exceptthat they'll execute the block repeatedly. That is, they loop.First, the conditional part of the statement is checked. If thecondition is met (if it is true for a <tt class="literal">while</tt> orfalse for an <tt class="literal">until</tt>), the block of the statement isexecuted.<blockquote><pre class="programlisting">while ($tickets_sold < 10000) { $available = 10000 - $tickets_sold; print "$available tickets are available. How many would you like: "; $purchase = <STDIN>; chomp($purchase); $tickets_sold += $purchase;}</pre></blockquote>Note that if the original condition is never met, the loop will never beentered at all. For example, if we've already sold 10,000 tickets, wemight want to have the next line of the program say something like:<blockquote><pre class="programlisting">print "This show is sold out, please come back later.\n";</pre></blockquote>In our Average Example earlier, line 4 reads:<blockquote><pre class="programlisting">while ($line = <GRADES>) {</pre></blockquote><a name="INDEX-309"></a>This assigns the next line to the variable <tt class="literal">$line</tt> and, as we explainedearlier, returns the value of <tt class="literal">$line</tt> so that the condition of the<tt class="literal">while</tt> statement can evaluate <tt class="literal">$line</tt> for truth. You might wonderwhether Perl will get a false negative on blank lines and exit the loopprematurely. The answer is that it won't. The reason is clear if youthink about everything we've said. The line input operator leaves thenewline on the end of the string, so a blank line has the value <tt class="literal">"\n"</tt>.And you know that <tt class="literal">"\n"</tt> is not one of the canonical false values. Sothe condition is true, and the loop continues even on blank lines.<a name="INDEX-310"></a><a name="INDEX-311"></a></p><p><a name="INDEX-312"></a>On the other hand, when we finally do reach the end of the file, theline input operator returns the undefined value, which always evaluatesto false. And the loop terminates, just when we wanted it to. There'sno need for an explicit test of the <tt class="literal">eof</tt> function in Perl,because the input operators are designed to work smoothly in aconditional context.</p><p>In fact, almost everything is designed to work smoothly in aconditional (Boolean) context. If you mention an array in a scalarcontext, the length of the array is returned. So you often see command-linearguments processed like this:<blockquote><pre class="programlisting">while (@ARGV) { process(shift @ARGV);}</pre></blockquote><a name="INDEX-313"></a> The<tt class="literal">shift</tt> operator removes one element from theargument list each time through the loop (and returns that element).The loop automatically exits when array <tt class="literal">@ARGV</tt> isexhausted, that is, when its length goes to 0. And 0 is already falsein Perl. In a sense, the array itself has become"false".<a href="#FOOTNOTE-21">[21]</a></p><blockquote class="footnote"><a name="FOOTNOTE-21"></a><p>[21] This is how Perl programmers think. So there'sno need to compare 0 to 0 to see if it's false. Despite the fact thatother languages force you to, don't go out of your way to write explicitcomparisons like <tt class="literal">while (@ARGV != 0)</tt>. That's justinefficient for both you and the computer. And anyone whohas to maintain your code.</p></blockquote><h3 class="sect3">1.6.2.2. The for statement</h3><p><a name="INDEX-314"></a><a name="INDEX-315"></a><a name="INDEX-316"></a> Another iterativestatement is the <tt class="literal">for</tt> loop. The<tt class="literal">for</tt> loop runs exactly like the<tt class="literal">while</tt> loop, but looks a good deal different. (Cprogrammers will find it very familiar though.)<blockquote><pre class="programlisting">for ($sold = 0; $sold < 10000; $sold += $purchase) { $available = 10000 - $sold; print "$available tickets are available. How many would you like: "; $purchase = <STDIN>; chomp($purchase);}</pre></blockquote>This <tt class="literal">for</tt> loop takes three expressions within theloop's parentheses: an expression to set the initial state of the loopvariable, a condition to test the loop variable, and an expression tomodify the state of the loop variable. When a <tt class="literal">for</tt>loop starts, the initial state is set and the truth condition ischecked. If the condition is true, the block is executed. When theblock finishes, the modification expression is executed, the truthcondition is again checked, and if true, the block is rerun with thenext value. As long as the truth condition remains true, the blockand the modification expression will continue to be executed. (Notethat only the middle expression is evaluated for its value. The firstand third expressions are evaluated only for their side effects, andthe resulting values are thrown away!)</p><h3 class="sect3">1.6.2.3. The foreach statement</h3><p><a name="INDEX-317"></a><a name="INDEX-318"></a><a name="INDEX-319"></a> The last ofPerl's iterative statements is the <tt class="literal">foreach</tt>statement, which is used to execute the same code for each of a knownset of scalars, such as an array:<blockquote><pre class="programlisting">foreach $user (@users) { if (-f "$home{$user}/.nexrc") { print "$user is cool... they use a perl-aware vi!\n"; }}</pre></blockquote><a name="INDEX-320"></a>Unlike the <tt class="literal">if</tt> and <tt class="literal">while</tt>statements, which provide scalar context to a conditional expression,the <tt class="literal">foreach</tt> statement provides a list context tothe expression in parentheses. So the expression is evaluated toproduce a list (not a scalar, even if there's only one scalar in thelist). Then each element of the list is aliased to the loop variablein turn, and the block of code is executed once for each listelement. Note that the loop variable refers to the element itself,rather than a copy of the element. Hence, modifying the loop variablealso modifies the original array.</p><p>You'll find many more <tt class="literal">foreach</tt> loops in the typicalPerl program than <tt class="literal">for</tt> loops, because it's very easyin Perl to generate the kinds of lists that <tt class="literal">foreach</tt>wants to iterate over. One idiom you'll often see is a loop toiterate over the sorted keys of a hash:<blockquote><pre class="programlisting">foreach $key (sort keys %hash) {</pre></blockquote>In fact, line 9 of our Average Example does precisely that.</p><h3 class="sect3">1.6.2.4. Breaking out: next and last</h3><p><a name="INDEX-321"></a><a name="INDEX-322"></a><a name="INDEX-323"></a>The <tt class="literal">next</tt> and <tt class="literal">last</tt> operators allow you to modify the flow of yourloop. It is not at all uncommon to have a special case; you may want toskip it, or you may want to quit when you encounter it. For example, ifyou are dealing with Unix accounts, you may want to skip the systemaccounts (like <em class="emphasis">root</em> or <em class="emphasis">lp</em>). The <tt class="literal">next</tt> operator would allow you toskip to the end of your current loop iteration, and start the nextiteration. The <tt class="literal">last</tt> operator would allow you to skip to the end ofyour block, as if your loop's test condition had returned false. This might beuseful if, for example, you are looking for a specific account and wantto quit as soon as you find it.<blockquote><pre class="programlisting">foreach $user (@users) { if ($user eq "root" or $user eq "lp") { next; } if ($user eq "special") { print "Found the special account.\n"; # do some processing last; }}</pre></blockquote>It's possible to break out of multilevel loops by labeling your loopsand specifying which loop you want to break out of. Together withstatement modifiers (another form of conditional which we'll talkabout later), this can make for extremely readable loop exits (if youhappen to think English is readable):<blockquote><pre class="programlisting">LINE: while ($line = <ARTICLE>) { last LINE if $line eq "\n"; # stop on first blank line next LINE if $line =~ /^#/; # skip comment lines # your ad here}</pre></blockquote></p><p>You may be saying, "Wait a minute, what's that funny<tt class="literal">^#</tt> thing there inside the leaning toothpicks? Thatdoesn't look much like English." And you're right. That's a patternmatch containing a regular expression (albeit a rather simple one). And that's what the next section is about. Perl is the best textprocessing language in the world, and regular expressions are at theheart of Perl's text processing.</p><a name="INDEX-324"></a><!-- BOTTOM NAV BAR --><hr width="515" align="left"><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch01_05.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="index.htm"><img src="../gifs/txthome.gif" alt="Home" border="0"></a></td><td align="right" valign="top" width="172"><a href="ch01_07.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr><tr><td align="left" valign="top" width="172">1.5. Operators</td><td align="center" valign="top" width="171"><a href="index/index.htm"><img src="../gifs/index.gif" alt="Book Index" border="0"></a></td><td align="right" valign="top" width="172">1.7. Regular Expressions</td></tr></table></div><hr width="515" align="left"><!-- LIBRARY NAV BAR --><img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p><font size="-1"><a href="copyrght.htm">Copyright © 2001</a> O'Reilly & Associates. All rights reserved.</font></p><map name="library-map"> <area shape="rect" coords="2,-1,79,99" href="../index.htm"><area shape="rect" coords="84,1,157,108" href="../perlnut/index.htm"><area shape="rect" coords="162,2,248,125" href="../prog/index.htm"><area shape="rect" coords="253,2,326,130" href="../advprog/index.htm"><area shape="rect" coords="332,1,407,112" href="../cookbook/index.htm"><area shape="rect" coords="414,2,523,103" href="../sysadmin/index.htm"></map><!-- END OF BODY --></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -