📄 perlfaq4.1
字号:
\& 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_time\en";.Ve.PPMost people try to use the time rather than the calendar to figure outdates, but that assumes that days are twenty-four hours each. Formost people, there are two days a year when they aren't: the switch toand from summer time throws this off. Let the modules do the work..Sh "Does Perl have a Year 2000 problem? Is Perl Y2K compliant?".IX Subsection "Does Perl have a Year 2000 problem? Is Perl Y2K compliant?"Short answer: No, Perl does not have a Year 2000 problem. Yes, Perl isY2K compliant (whatever that means). The programmers you've hired touse it, however, probably are not..PPLong answer: The question belies a true understanding of the issue.Perl is just as Y2K compliant as your pencil\*(--no more, and no less.Can you use your pencil to write a non\-Y2K\-compliant memo? Of courseyou can. Is that the pencil's fault? Of course it isn't..PPThe date and time functions supplied with Perl (gmtime and localtime)supply adequate information to determine the year well beyond 2000(2038 is when trouble strikes for 32\-bit machines). The year returnedby these functions when used in a list context is the year minus 1900.For years between 1910 and 1999 this \fIhappens\fR to be a 2\-digit decimalnumber. To avoid the year 2000 problem simply do not treat the year asa 2\-digit number. It isn't..PPWhen \fIgmtime()\fR and \fIlocaltime()\fR are used in scalar context they returna timestamp string that contains a fully-expanded year. For example,\&\f(CW\*(C`$timestamp = gmtime(1005613200)\*(C'\fR sets \f(CW$timestamp\fR to \*(L"Tue Nov 13 01:00:002001\*(R". There's no year 2000 problem here..PPThat doesn't mean that Perl can't be used to create non\-Y2K compliantprograms. It can. But so can your pencil. It's the fault of the user,not the language. At the risk of inflaming the \s-1NRA:\s0 \*(L"Perl doesn'tbreak Y2K, people do.\*(R" See http://www.perl.org/about/y2k.html fora longer exposition..SH "Data: Strings".IX Header "Data: Strings".Sh "How do I validate input?".IX Subsection "How do I validate input?"(contributed by brian d foy).PPThere are many ways to ensure that values are what you expect orwant to accept. Besides the specific examples that we cover in theperlfaq, you can also look at the modules with \*(L"Assert\*(R" and \*(L"Validate\*(R"in their names, along with other modules such as \f(CW\*(C`Regexp::Common\*(C'\fR..PPSome modules have validation for particular types of input, suchas \f(CW\*(C`Business::ISBN\*(C'\fR, \f(CW\*(C`Business::CreditCard\*(C'\fR, \f(CW\*(C`Email::Valid\*(C'\fR,and \f(CW\*(C`Data::Validate::IP\*(C'\fR..Sh "How do I unescape a string?".IX Subsection "How do I unescape a string?"It depends just what you mean by \*(L"escape\*(R". \s-1URL\s0 escapes are dealtwith in perlfaq9. Shell escapes with the backslash (\f(CW\*(C`\e\*(C'\fR)character are removed with.PP.Vb 1\& s/\e\e(.)/$1/g;.Ve.PPThis won't expand \f(CW"\en"\fR or \f(CW"\et"\fR or any other special escapes..Sh "How do I remove consecutive pairs of characters?".IX Subsection "How do I remove consecutive pairs of characters?"(contributed by brian d foy).PPYou can use the substitution operator to find pairs of characters (orruns of characters) and replace them with a single instance. In thissubstitution, we find a character in \f(CW\*(C`(.)\*(C'\fR. The memory parenthesesstore the matched character in the back-reference \f(CW\*(C`\e1\*(C'\fR and we usethat to require that the same thing immediately follow it. We replacethat part of the string with the character in \f(CW$1\fR..PP.Vb 1\& s/(.)\e1/$1/g;.Ve.PPWe can also use the transliteration operator, \f(CW\*(C`tr///\*(C'\fR. In thisexample, the search list side of our \f(CW\*(C`tr///\*(C'\fR contains nothing, butthe \f(CW\*(C`c\*(C'\fR option complements that so it contains everything. Thereplacement list also contains nothing, so the transliteration isalmost a no-op since it won't do any replacements (or more exactly,replace the character with itself). However, the \f(CW\*(C`s\*(C'\fR option squashesduplicated and consecutive characters in the string so a characterdoes not show up next to itself.PP.Vb 2\& my $str = \*(AqHaarlem\*(Aq; # in the Netherlands\& $str =~ tr///cs; # Now Harlem, like in New York.Ve.Sh "How do I expand function calls in a string?".IX Subsection "How do I expand function calls in a string?"(contributed by brian d foy).PPThis is documented in perlref, and although it's not the easiestthing to read, it does work. In each of these examples, we call thefunction inside the braces used to dereference a reference. If wehave more than one return value, we can construct and dereference ananonymous array. In this case, we call the function in list context..PP.Vb 1\& print "The time values are @{ [localtime] }.\en";.Ve.PPIf we want to call the function in scalar context, we have to do a bitmore work. We can really have any code we like inside the braces, sowe simply have to end with the scalar reference, although how you dothat is up to you, and you can use code inside the braces. Note thatthe use of parens creates a list context, so we need \f(CW\*(C`scalar\*(C'\fR toforce the scalar context on the function:.PP.Vb 1\& print "The time is ${\e(scalar localtime)}.\en"\&\& print "The time is ${ my $x = localtime; \e$x }.\en";.Ve.PPIf your function already returns a reference, you don't need to createthe reference yourself..PP.Vb 1\& sub timestamp { my $t = localtime; \e$t }\&\& print "The time is ${ timestamp() }.\en";.Ve.PPThe \f(CW\*(C`Interpolation\*(C'\fR module can also do a lot of magic for you. You canspecify a variable name, in this case \f(CW\*(C`E\*(C'\fR, to set up a tied hash thatdoes the interpolation for you. It has several other methods to do thisas well..PP.Vb 2\& use Interpolation E => \*(Aqeval\*(Aq;\& print "The time values are $E{localtime()}.\en";.Ve.PPIn most cases, it is probably easier to simply use string concatenation,which also forces scalar context..PP.Vb 1\& print "The time is " . localtime() . ".\en";.Ve.Sh "How do I find matching/nesting anything?".IX Subsection "How do I find matching/nesting anything?"This isn't something that can be done in one regular expression, nomatter how complicated. To find something between two singlecharacters, a pattern like \f(CW\*(C`/x([^x]*)x/\*(C'\fR will get the interveningbits in \f(CW$1\fR. For multiple ones, then something more like\&\f(CW\*(C`/alpha(.*?)omega/\*(C'\fR would be needed. But none of these deals withnested patterns. For balanced expressions using \f(CW\*(C`(\*(C'\fR, \f(CW\*(C`{\*(C'\fR, \f(CW\*(C`[\*(C'\fR or\&\f(CW\*(C`<\*(C'\fR as delimiters, use the \s-1CPAN\s0 module Regexp::Common, or see\&\*(L"(??{ code })\*(R" in perlre. For other cases, you'll have to write aparser..PPIf you are serious about writing a parser, there are a number ofmodules or oddities that will make your life a lot easier. There arethe \s-1CPAN\s0 modules \f(CW\*(C`Parse::RecDescent\*(C'\fR, \f(CW\*(C`Parse::Yapp\*(C'\fR, and\&\f(CW\*(C`Text::Balanced\*(C'\fR; and the \f(CW\*(C`byacc\*(C'\fR program. Starting from perl 5.8the \f(CW\*(C`Text::Balanced\*(C'\fR is part of the standard distribution..PPOne simple destructive, inside-out approach that you might try is topull out the smallest nesting parts one at a time:.PP.Vb 3\& while (s/BEGIN((?:(?!BEGIN)(?!END).)*)END//gs) {\& # do something with $1\& }.Ve.PPA more complicated and sneaky approach is to make Perl's regularexpression engine do it for you. This is courtesy Dean Inada, andrather has the nature of an Obfuscated Perl Contest entry, but itreally does work:.PP.Vb 3\& # $_ contains the string to parse\& # BEGIN and END are the opening and closing markers for the\& # nested text.\&\& @( = (\*(Aq(\*(Aq,\*(Aq\*(Aq);\& @) = (\*(Aq)\*(Aq,\*(Aq\*(Aq);\& ($re=$_)=~s/((BEGIN)|(END)|.)/$)[!$3]\eQ$1\eE$([!$2]/gs;\& @$ = (eval{/$re/},$@!~/unmatched/i);\& print join("\en",@$[0..$#$]) if( $$[\-1] );.Ve.Sh "How do I reverse a string?".IX Subsection "How do I reverse a string?"Use \f(CW\*(C`reverse()\*(C'\fR in scalar context, as documented in\&\*(L"reverse\*(R" in perlfunc..PP.Vb 1\& $reversed = reverse $string;.Ve.Sh "How do I expand tabs in a string?".IX Subsection "How do I expand tabs in a string?"You can do it yourself:.PP.Vb 1\& 1 while $string =~ s/\et+/\*(Aq \*(Aq x (length($&) * 8 \- length($\`) % 8)/e;.Ve.PPOr you can just use the \f(CW\*(C`Text::Tabs\*(C'\fR module (part of the standard Perldistribution)..PP.Vb 2\& use Text::Tabs;\& @expanded_lines = expand(@lines_with_tabs);.Ve.Sh "How do I reformat a paragraph?".IX Subsection "How do I reformat a paragraph?"Use \f(CW\*(C`Text::Wrap\*(C'\fR (part of the standard Perl distribution):.PP.Vb 2\& use Text::Wrap;\& print wrap("\et", \*(Aq \*(Aq, @paragraphs);.Ve.PPThe paragraphs you give to \f(CW\*(C`Text::Wrap\*(C'\fR should not contain embeddednewlines. \f(CW\*(C`Text::Wrap\*(C'\fR doesn't justify the lines (flush-right)..PPOr use the \s-1CPAN\s0 module \f(CW\*(C`Text::Autoformat\*(C'\fR. Formatting files can beeasily done by making a shell alias, like so:.PP.Vb 2\& alias fmt="perl \-i \-MText::Autoformat \-n0777 \e\& \-e \*(Aqprint autoformat $_, {all=>1}\*(Aq $*".Ve.PPSee the documentation for \f(CW\*(C`Text::Autoformat\*(C'\fR to appreciate its manycapabilities..Sh "How can I access or change N characters of a string?".IX Subsection "How can I access or change N characters of a string?"You can access the first characters of a string with \fIsubstr()\fR.To get the first character, for example, start at position 0and grab the string of length 1..PP.Vb 2\& $string = "Just another Perl Hacker";\& $first_char = substr( $string, 0, 1 ); # \*(AqJ\*(Aq.Ve.PPTo change part of a string, you can use the optional fourthargument which is the replacement string..PP.Vb 1\& substr( $string, 13, 4, "Perl 5.8.0" );.Ve.PPYou can also use \fIsubstr()\fR as an lvalue..PP.Vb 1\& substr( $string, 13, 4 ) = "Perl 5.8.0";.Ve.Sh "How do I change the Nth occurrence of something?".IX Subsection "How do I change the Nth occurrence of something?"You have to keep track of N yourself. For example, let's say you wantto change the fifth occurrence of \f(CW"whoever"\fR or \f(CW"whomever"\fR into\&\f(CW"whosoever"\fR or \f(CW"whomsoever"\fR, case insensitively. Theseall assume that \f(CW$_\fR contains the string to be altered..PP.Vb 6\& $count = 0;\& s{((whom?)ever)}{\& ++$count == 5 # is it the 5th?\& ? "${2}soever" # yes, swap\& : $1 # renege and leave it there\& }ige;.Ve.PPIn the more general case, you can use the \f(CW\*(C`/g\*(C'\fR modifier in a \f(CW\*(C`while\*(C'\fRloop, keeping count of matches..PP.Vb 8\& $WANT = 3;\& $count = 0;\& $_ = "One fish two fish red fish blue fish";\& while (/(\ew+)\es+fish\eb/gi) {\& if (++$count == $WANT) {\& print "The third fish is a $1 one.\en";\& }\& }.Ve.PPThat prints out: \f(CW"The third fish is a red one."\fR You can also use arepetition count and repeated pattern like this:.PP.Vb 1\& /(?:\ew+\es+fish\es+){2}(\ew+)\es+fish/i;.Ve.Sh "How can I count the number of occurrences of a substring within a string?".IX Subsection "How can I count the number of occurrences of a substring within a string?"There are a number of ways, with varying efficiency. If you want acount of a certain single character (X) within a string, you can use the\&\f(CW\*(C`tr///\*(C'\fR function like so:.PP.Vb 3\& $string = "ThisXlineXhasXsomeXx\*(AqsXinXit";\& $count = ($string =~ tr/X//);\& print "There are $count X characters in the string";.Ve.PPThis is fine if you are just looking for a single character. However,if you are trying to count multiple character substrings within alarger string, \f(CW\*(C`tr///\*(C'\fR won't work. What you can do is wrap a \fIwhile()\fRloop around a global pattern match. For example, let's count negativeintegers:.PP.Vb 3\& $string = "\-9 55 48 \-2 23 \-76 4 14 \-44";\& while ($string =~ /\-\ed+/g) { $count++ }\& print "There are $count negative numbers in the string";.Ve.PPAnother version uses a global match in list context, then assigns theresult to a scalar, producing a count of the number of matches..PP.Vb 1\& $count = () = $string =~ /\-\ed+/g;.Ve.Sh "How do I capitalize all the words on one line?".IX Subsection "How do I capitalize all the words on one line?"To make the first letter of each word upper case:.PP.Vb 1\& $line =~ s/\eb(\ew)/\eU$1/g;.Ve.PPThis has the strange effect of turning "\f(CW\*(C`don\*(Aqt do it\*(C'\fR\*(L" into \*(R"\f(CW\*(C`Don\*(AqTDo It\*(C'\fR". Sometimes you might want this. Other times you might need amore thorough solution (Suggested by brian d foy):.PP.Vb 6\& $string =~ s/ (\& (^\ew) #at the beginning of the line\& | # or\& (\es\ew) #preceded by whitespace\& )\& /\eU$1/xg;\&\& $string =~ s/([\ew\*(Aq]+)/\eu\eL$1/g;.Ve.PPTo make the whole line upper case:.PP.Vb 1\& $line = uc($line);.Ve.PP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -