perlfaq4.pod
来自「视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.」· POD 代码 · 共 2,029 行 · 第 1/5 页
POD
2,029 行
This is sometimes referred to as putting something into "titlecase", but that's not quite accurate. Consider the propercapitalization of the movie I<Dr. Strangelove or: How I Learned toStop Worrying and Love the Bomb>, for example.Damian Conway's L<Text::Autoformat> module provides some smartcase transformations: use Text::Autoformat; my $x = "Dr. Strangelove or: How I Learned to Stop ". "Worrying and Love the Bomb"; print $x, "\n"; for my $style (qw( sentence title highlight )) { print autoformat($x, { case => $style }), "\n"; }=head2 How can I split a [character] delimited string except when inside [character]?Several modules can handle this sort of parsing--C<Text::Balanced>,C<Text::CSV>, C<Text::CSV_XS>, and C<Text::ParseWords>, among others.Take the example case of trying to split a string that iscomma-separated into its different fields. You can't use C<split(/,/)>because you shouldn't split if the comma is inside quotes. Forexample, take a data line like this: SAR001,"","Cimetrix, Inc","Bob Smith","CAM",N,8,1,0,7,"Error, Core Dumped"Due to the restriction of the quotes, this is a fairly complexproblem. Thankfully, we have Jeffrey Friedl, author ofI<Mastering Regular Expressions>, to handle these for us. Hesuggests (assuming your string is contained in C<$text>): @new = (); push(@new, $+) while $text =~ m{ "([^\"\\]*(?:\\.[^\"\\]*)*)",? # groups the phrase inside the quotes | ([^,]+),? | , }gx; push(@new, undef) if substr($text,-1,1) eq ',';If you want to represent quotation marks inside aquotation-mark-delimited field, escape them with backslashes (eg,C<"like \"this\"">.Alternatively, the C<Text::ParseWords> module (part of the standardPerl distribution) lets you say: use Text::ParseWords; @new = quotewords(",", 0, $text);=head2 How do I strip blank space from the beginning/end of a string?(contributed by brian d foy)A substitution can do this for you. For a single line, you want toreplace all the leading or trailing whitespace with nothing. Youcan do that with a pair of substitutions. s/^\s+//; s/\s+$//;You can also write that as a single substitution, although it turnsout the combined statement is slower than the separate ones. Thatmight not matter to you, though. s/^\s+|\s+$//g;In this regular expression, the alternation matches either at thebeginning or the end of the string since the anchors have a lowerprecedence than the alternation. With the C</g> flag, the substitutionmakes all possible matches, so it gets both. Remember, the trailingnewline matches the C<\s+>, and the C<$> anchor can match to thephysical end of the string, so the newline disappears too. Just addthe 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. while( <> ) { s/^\s+|\s+$//g; print "$_\n"; }For a multi-line string, you can apply the regular expressionto each logical line in the string by adding the C</m> flag (for"multi-line"). With the C</m> flag, the C<$> matches I<before> anembedded newline, so it doesn't remove it. It still removes thenewline 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 stringand 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?In the following examples, C<$pad_len> is the length to which you wishto pad the string, C<$text> or C<$num> contains the string to be padded,and C<$pad_char> contains the padding character. You can use a singlecharacter string constant instead of the C<$pad_char> variable if youknow what it is in advance. And in the same way you can use an integer inplace of C<$pad_len> if you know the pad length in advance.The simplest method uses the C<sprintf> function. It can pad on the leftor right with blanks and on the left with zeroes and it will nottruncate the result. The C<pack> function can only pad strings on theright with blanks and it will truncate the result to a maximum length ofC<$pad_len>. # Left padding a string with blanks (no truncation): $padded = sprintf("%${pad_len}s", $text); $padded = sprintf("%*s", $pad_len, $text); # same thing # Right padding a string with blanks (no truncation): $padded = sprintf("%-${pad_len}s", $text); $padded = sprintf("%-*s", $pad_len, $text); # same thing # Left padding a number with 0 (no truncation): $padded = sprintf("%0${pad_len}d", $num); $padded = sprintf("%0*d", $pad_len, $num); # same thing # Right padding a string with blanks using pack (will truncate): $padded = pack("A$pad_len",$text);If you need to pad with a character other than blank or zero you can useone of the following methods. They all generate a pad string with theC<x> operator and combine that with C<$text>. These methods donot truncate C<$text>.Left and right padding with any character, creating a new string: $padded = $pad_char x ( $pad_len - length( $text ) ) . $text; $padded = $text . $pad_char x ( $pad_len - length( $text ) );Left and right padding with any character, modifying C<$text> directly: substr( $text, 0, 0 ) = $pad_char x ( $pad_len - length( $text ) ); $text .= $pad_char x ( $pad_len - length( $text ) );=head2 How do I extract selected columns from a string?(contributed by brian d foy)If you know where the columns that contain the data, you canuse C<substr> to extract a single column. my $column = substr( $line, $start_column, $length );You can use C<split> if the columns are separated by whitespace orsome other delimiter, as long as whitespace or the delimiter cannotappear as part of the data. my $line = ' fred barney betty '; my @columns = split /\s+/, $line; # ( '', 'fred', 'barney', 'betty' ); my $line = 'fred||barney||betty'; my @columns = split /\|/, $line; # ( 'fred', '', 'barney', '', 'betty' );If you want to work with comma-separated values, don't do this sincethat format is a bit more complicated. Use one of the modules thathandle that fornat, such as C<Text::CSV>, C<Text::CSV_XS>, orC<Text::CSV_PP>.If you want to break apart an entire line of fixed columns, you can useC<unpack> with the A (ASCII) format. by using a number after the formatspecifier, you can denote the column width. See the C<pack> and C<unpack>entries in L<perlfunc> for more details. my @fields = unpack( $line, "A8 A8 A8 A16 A4" );Note that spaces in the format argument to C<unpack> do not denote literalspaces. If you have space separated data, you may want C<split> instead.=head2 How do I find the soundex value of a string?(contributed by brian d foy)You can use the Text::Soundex module. If you want to do fuzzy or closematching, you might also try the C<String::Approx>, andC<Text::Metaphone>, and C<Text::DoubleMetaphone> modules.=head2 How can I expand variables in text strings?(contributed by brian d foy)If you can avoid it, don't, or if you can use a templating system,such as C<Text::Template> or C<Template> Toolkit, do that instead. Youmight even be able to get the job done with C<sprintf> or C<printf>: my $string = sprintf 'Say hello to %s and %s', $foo, $bar;However, for the one-off simple case where I don't want to pull out afull templating system, I'll use a string that has two Perl scalarvariables in it. In this example, I want to expand C<$foo> and C<$bar>to their variable's values: my $foo = 'Fred'; my $bar = 'Barney'; $string = 'Say hello to $foo and $bar';One way I can do this involves the substitution operator and a doubleC</e> flag. The first C</e> evaluates C<$1> on the replacement side andturns it into C<$foo>. The second /e starts with C<$foo> and replacesit with its value. C<$foo>, then, turns into 'Fred', and that's finallywhat's left in the string: $string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'The C</e> will also silently ignore violations of strict, replacingundefined variable names with the empty string. Since I'm using theC</e> flag (twice even!), I have all of the same security problems I have with C<eval> in its string form. If there's something odd inC<$foo>, perhaps something like C<@{[ system "rm -rf /" ]}>, thenI could get myself in trouble.To get around the security problem, I could also pull the values froma hash instead of evaluating variable names. Using a single C</e>, Ican check the hash to ensure the value exists, and if it doesn't, Ican replace the missing value with a marker, in this case C<???> tosignal that I missed something: my $string = 'This has $foo and $bar'; my %Replacements = ( foo => 'Fred', ); # $string =~ s/\$(\w+)/$Replacements{$1}/g; $string =~ s/\$(\w+)/ exists $Replacements{$1} ? $Replacements{$1} : '???' /eg; print $string;=head2 What's wrong with always quoting "$vars"?The problem is that those double-quotes forcestringification--coercing numbers and references into strings--evenwhen you don't want them to be strings. Think of it this way:double-quote expansion is used to produce new strings. If you alreadyhave a string, why do you need more?If you get used to writing odd things like these: print "$var"; # BAD $new = "$old"; # BAD somefunc("$var"); # BADYou'll be in trouble. Those should (in 99.8% of the cases) bethe simpler and more direct: print $var; $new = $old; somefunc($var);Otherwise, besides slowing you down, you're going to break code whenthe thing in the scalar is actually neither a string nor a number, buta reference: func(\@array); sub func { my $aref = shift; my $oref = "$aref"; # WRONG }You can also get into subtle problems on those few operations in Perlthat actually do care about the difference between a string and anumber, such as the magical C<++> autoincrement operator or thesyscall() function.Stringification also destroys arrays. @lines = `command`; print "@lines"; # WRONG - extra blanks print @lines; # right=head2 Why don't my E<lt>E<lt>HERE documents work?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.=item You can't (easily) have any space in front of the tag.=backIf you want to indent the text in the here document, youcan do this: # all in one ($VAR = <<HERE_TARGET) =~ s/^\s+//gm; your text goes here HERE_TARGETBut the HERE_TARGET must still be flush against the margin.If you want that indented also, you'll have to quotein the indentation. ($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 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. sub fix { local $_ = shift; my ($white, $leader); # common whitespace and common leading string if (/^\s*(?:([^\w\s]+)(\s*).*\n)(?:\s*\1\2?.*\n)+$/) { ($white, $leader) = ($2, quotemeta($1)); } else { ($white, $leader) = (/^(\s+)/, ''); } s/^\s*?$leader(?:$white)?//gm; return $_; }This works with leading special strings, dynamically determined: $remember_the_main = fix<<' MAIN_INTERPRETER_LOOP'; @@@ int @@@ runops() { @@@ SAVEI32(runlevel); @@@ runlevel++; @@@ while ( op = (*op->op_ppaddr)() ); @@@ TAINT_NOT; @@@ return 0; @@@ } MAIN_INTERPRETER_LOOPOr with a fixed amount of leading whitespace, with remainingindentation correctly preserved: $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=head1 Data: Arrays=head2 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 C<foreach()>across a list. C<@> variables are arrays, anonymous arrays arearrays, arrays in scalar context behave like the number of elements inthem, subroutines access their arguments through the array C<@_>, andC<push>/C<pop>/C<shift> only work on arrays.As a side note, there's no such thing as a list in scalar context.When you say $scalar = (2, 5, 7, 9);you'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.=head2 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).Sometimes it doesn't make a difference, but sometimes it does.For example, compare: $good[0] = `some program that outputs several lines`;with @bad[0] = `same program that outputs several lines`;The C<use warnings> pragma and the B<-w> flag will warn you about these
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?