This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Rename perlunintro to perluniintro; regen toc.
[perl5.git] / pod / perlfaq6.pod
index 535e464..be7e8ec 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
-perlfaq6 - Regexps ($Revision: 1.17 $, $Date: 1997/04/24 22:44:10 $)
+perlfaq6 - Regexes ($Revision: 1.4 $, $Date: 2001/11/09 08:06:04 $)
 
 =head1 DESCRIPTION
 
@@ -8,8 +8,9 @@ This section is surprisingly small because the rest of the FAQ is
 littered with answers involving regular expressions.  For example,
 decoding a URL and checking whether something is a number are handled
 with regular expressions, but those answers are found elsewhere in
-this document (in the section on Data and the Networking one on
-networking, to be precise).
+this document (in L<perlfaq9>: ``How do I decode or create those %-encodings 
+on the web'' and L<perfaq4>: ``How do I determine whether a scalar is
+a number/whole/integer/float'', to be precise).
 
 =head2 How can I hope to use regular expressions without creating illegible and unmaintainable code?
 
@@ -18,18 +19,18 @@ understandable.
 
 =over 4
 
-=item Comments Outside the Regexp
+=item Comments Outside the Regex
 
 Describe what you're doing and how you're doing it, using normal Perl
 comments.
 
     # turn the line into the first word, a colon, and the
     # number of characters on the rest of the line
-    s/^(\w+)(.*)/ lc($1) . ":" . length($2) /ge;
+    s/^(\w+)(.*)/ lc($1) . ":" . length($2) /meg;
 
-=item Comments Inside the Regexp
+=item Comments Inside the Regex
 
-The C</x> modifier causes whitespace to be ignored in a regexp pattern
+The C</x> modifier causes whitespace to be ignored in a regex pattern
 (except in a character class), and also allows you to use normal
 comments there, too.  As you can imagine, whitespace and comments help
 a lot.
@@ -69,8 +70,9 @@ delimiter within the pattern:
 
 =head2 I'm having trouble matching over more than one line.  What's wrong?
 
-Either you don't have newlines in your string, or you aren't using the
-correct modifier(s) on your pattern.
+Either you don't have more than one line in the string you're looking at
+(probably), or else you aren't using the correct modifier(s) on your
+pattern (possibly).
 
 There are many ways to get multiline data into a string.  If you want
 it to happen automatically while reading input, you'll want to set $/
@@ -94,7 +96,7 @@ record read in.
 
     $/ = '';           # read in more whole paragraph, not just one line
     while ( <> ) {
-       while ( /\b(\w\S+)(\s+\1)+\b/gi ) {
+       while ( /\b([\w'-]+)(\s+\1)+\b/gi ) {   # word starts alpha
            print "Duplicate $1 at paragraph $.\n";
        }
     }
@@ -113,7 +115,7 @@ Here's code that finds everything between START and END in a paragraph:
 
     undef $/;                  # read in whole file, not just one line or paragraph
     while ( <> ) {
-       while ( /START(.*?)END/sm ) { # /s makes . cross line boundaries
+       while ( /START(.*?)END/sgm ) { # /s makes . cross line boundaries
            print "$1\n";
        }
     }
@@ -127,12 +129,22 @@ L<perlop>):
 
 If you wanted text and not lines, you would use
 
-    perl -0777 -pe 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...
+    perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...
 
 But if you want nested occurrences of C<START> through C<END>, you'll
 run up against the problem described in the question in this section
 on matching balanced text.
 
+Here's another example of using C<..>:
+
+    while (<>) {
+        $in_header =   1  .. /^$/;
+        $in_body   = /^$/ .. eof();
+       # now choose between them
+    } continue {
+       reset if eof();         # fix $.
+    } 
+
 =head2 I put a regular expression into $/ but it didn't work. What's wrong?
 
 $/ must be a string, not a regular expression.  Awk has to be better
@@ -164,13 +176,63 @@ appear within a certain time.
     $file->waitfor('/second line\n/');
     print $file->getline;
 
-=head2 How do I substitute case insensitively on the LHS, but preserving case on the RHS?
+=head2 How do I substitute case insensitively on the LHS while preserving case on the RHS?
+
+Here's a lovely Perlish solution by Larry Rosler.  It exploits
+properties of bitwise xor on ASCII strings.
+
+    $_= "this is a TEsT case";
+
+    $old = 'test';
+    $new = 'success';
+
+    s{(\Q$old\E)}
+     { uc $new | (uc $1 ^ $1) .
+       (uc(substr $1, -1) ^ substr $1, -1) x
+           (length($new) - length $1)
+     }egi;
+
+    print;
 
-It depends on what you mean by "preserving case".  The following
-script makes the substitution have the same case, letter by letter, as
-the original.  If the substitution has more characters than the string
-being substituted, the case of the last character is used for the rest
-of the substitution.
+And here it is as a subroutine, modeled after the above:
+
+    sub preserve_case($$) {
+       my ($old, $new) = @_;
+       my $mask = uc $old ^ $old;
+
+       uc $new | $mask .
+           substr($mask, -1) x (length($new) - length($old))        
+    }
+
+    $a = "this is a TEsT case";
+    $a =~ s/(test)/preserve_case($1, "success")/egi;
+    print "$a\n";
+
+This prints:
+
+    this is a SUcCESS case
+
+As an alternative, to keep the case of the replacement word if it is
+longer than the original, you can use this code, by Jeff Pinyan:
+
+  sub preserve_case {
+    my ($from, $to) = @_;
+    my ($lf, $lt) = map length, @_;
+    
+    if ($lt < $lf) { $from = substr $from, 0, $lt }
+    else { $from .= substr $to, $lf }
+    
+    return uc $to | ($from ^ uc $from);
+  }
+
+This changes the sentence to "this is a SUcCess case."
+
+Just to show that C programmers can write C in any programming language,
+if you prefer a more C-like solution, the following script makes the
+substitution have the same case, letter by letter, as the original.
+(It also happens to run about 240% slower than the Perlish solution runs.)
+If the substitution has more characters than the string being substituted,
+the case of the last character is used for the rest of the substitution.
 
     # Original by Nathan Torkington, massaged by Jeffrey Friedl
     #
@@ -203,15 +265,7 @@ of the substitution.
         return $new;
     }
 
-    $a = "this is a TEsT case";
-    $a =~ s/(test)/preserve_case($1, "success")/gie;
-    print "$a\n";
-
-This prints:
-
-    this is a SUcCESS case
-
-=head2 How can I make C<\w> match accented characters?
+=head2 How can I make C<\w> match national character sets?
 
 See L<perllocale>.
 
@@ -221,41 +275,42 @@ One alphabetic character would be C</[^\W\d_]/>, no matter what locale
 you're in.  Non-alphabetics would be C</[\W\d_]/> (assuming you don't
 consider an underscore a letter).
 
-=head2 How can I quote a variable to use in a regexp?
+=head2 How can I quote a variable to use in a regex?
 
 The Perl parser will expand $variable and @variable references in
 regular expressions unless the delimiter is a single quote.  Remember,
 too, that the right-hand side of a C<s///> substitution is considered
 a double-quoted string (see L<perlop> for more details).  Remember
-also that any regexp special characters will be acted on unless you
+also that any regex special characters will be acted on unless you
 precede the substitution with \Q.  Here's an example:
 
     $string = "to die?";
     $lhs = "die?";
-    $rhs = "sleep no more";
+    $rhs = "sleep, no more";
 
     $string =~ s/\Q$lhs/$rhs/;
     # $string is now "to sleep no more"
 
-Without the \Q, the regexp would also spuriously match "di".
+Without the \Q, the regex would also spuriously match "di".
 
 =head2 What is C</o> really for?
 
 Using a variable in a regular expression match forces a re-evaluation
-(and perhaps recompilation) each time through.  The C</o> modifier
-locks in the regexp the first time it's used.  This always happens in a
-constant regular expression, and in fact, the pattern was compiled
-into the internal format at the same time your entire program was.
+(and perhaps recompilation) each time the regular expression is
+encountered.  The C</o> modifier locks in the regex the first time
+it's used.  This always happens in a constant regular expression, and
+in fact, the pattern was compiled into the internal format at the same
+time your entire program was.
 
 Use of C</o> is irrelevant unless variable interpolation is used in
-the pattern, and if so, the regexp engine will neither know nor care
+the pattern, and if so, the regex engine will neither know nor care
 whether the variables change after the pattern is evaluated the I<very
 first> time.
 
 C</o> is often used to gain an extra measure of efficiency by not
 performing subsequent evaluations when you know it won't matter
 (because you know the variables won't change), or more rarely, when
-you don't want the regexp to notice if they do.
+you don't want the regex to notice if they do.
 
 For example, here's a "paragrep" program:
 
@@ -275,35 +330,88 @@ For example, this one-liner
 will work in many but not all cases.  You see, it's too simple-minded for
 certain kinds of C programs, in particular, those with what appear to be
 comments in quoted strings.  For that, you'd need something like this,
-created by Jeffrey Friedl:
+created by Jeffrey Friedl and later modified by Fred Curtis.
 
     $/ = undef;
     $_ = <>;
-    s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|\n+|.[^/"'\\]*)#$2#g;
+    s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#$2#gs
     print;
 
 This could, of course, be more legibly written with the C</x> modifier, adding
-whitespace and comments.
+whitespace and comments.  Here it is expanded, courtesy of Fred Curtis.
+
+    s{
+       /\*         ##  Start of /* ... */ comment
+       [^*]*\*+    ##  Non-* followed by 1-or-more *'s
+       (
+         [^/*][^*]*\*+
+       )*          ##  0-or-more things which don't start with /
+                   ##    but do end with '*'
+       /           ##  End of /* ... */ comment
+
+     |         ##     OR  various things which aren't comments:
+
+       (
+         "           ##  Start of " ... " string
+         (
+           \\.           ##  Escaped char
+         |               ##    OR
+           [^"\\]        ##  Non "\
+         )*
+         "           ##  End of " ... " string
+
+       |         ##     OR
+
+         '           ##  Start of ' ... ' string
+         (
+           \\.           ##  Escaped char
+         |               ##    OR
+           [^'\\]        ##  Non '\
+         )*
+         '           ##  End of ' ... ' string
+
+       |         ##     OR
+
+         .           ##  Anything other char
+         [^/"'\\]*   ##  Chars which doesn't start a comment, string or escape
+       )
+     }{$2}gxs;
+
+A slight modification also removes C++ comments:
+
+    s#/\*[^*]*\*+([^/*][^*]*\*+)*/|//[^\n]*|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#$2#gs;
 
 =head2 Can I use Perl regular expressions to match balanced text?
 
-Although Perl regular expressions are more powerful than "mathematical"
-regular expressions, because they feature conveniences like backreferences
-(C<\1> and its ilk), they still aren't powerful enough. You still need
-to use non-regexp techniques to parse balanced text, such as the text
-enclosed between matching parentheses or braces, for example.
+Historically, Perl regular expressions were not capable of matching
+balanced text.  As of more recent versions of perl including 5.6.1
+experimental features have been added that make it possible to do this.
+Look at the documentation for the (??{ }) construct in recent perlre manual
+pages to see an example of matching balanced parentheses.  Be sure to take
+special notice of the  warnings present in the manual before making use
+of this feature.
+
+CPAN contains many modules that can be useful for matching text
+depending on the context.  Damian Conway provides some useful
+patterns in Regexp::Common.  The module Text::Balanced provides a
+general solution to this problem.
+
+One of the common applications of balanced text matching is working
+with XML and HTML.  There are many modules available that support
+these needs.  Two examples are HTML::Parser and XML::Parser. There
+are many others.
 
 An elaborate subroutine (for 7-bit ASCII only) to pull out balanced
 and possibly nested single chars, like C<`> and C<'>, C<{> and C<}>,
 or C<(> and C<)> can be found in
-http://www.perl.com/CPAN/authors/id/TOMC/scripts/pull_quotes.gz .
+http://www.cpan.org/authors/id/TOMC/scripts/pull_quotes.gz .
 
-The C::Scan module from CPAN contains such subs for internal usage,
+The C::Scan module from CPAN also contains such subs for internal use,
 but they are undocumented.
 
-=head2 What does it mean that regexps are greedy?  How can I get around it?
+=head2 What does it mean that regexes are greedy?  How can I get around it?
 
-Most people mean that greedy regexps match as much as they can.
+Most people mean that greedy regexes match as much as they can.
 Technically speaking, it's actually the quantifiers (C<?>, C<*>, C<+>,
 C<{}>) that are greedy rather than the whole pattern; Perl prefers local
 greed and immediate gratification to overall greed.  To get non-greedy
@@ -321,7 +429,7 @@ expression engine to find a match as quickly as possible and pass
 control on to whatever is next in line, like you would if you were
 playing hot potato.
 
-=head2  How do I process each word on each line?
+=head2 How do I process each word on each line?
 
 Use the split function:
 
@@ -334,7 +442,8 @@ Use the split function:
 Note that this isn't really a word in the English sense; it's just
 chunks of consecutive non-whitespace characters.
 
-To work with only alphanumeric sequences, you might consider
+To work with only alphanumeric sequences (including underscores), you
+might consider
 
     while (<>) {
        foreach $word (m/(\w+)/g) {
@@ -368,7 +477,8 @@ regular expression:
        print "$count $line";
     }
 
-If you want these output in a sorted order, see the section on Hashes.
+If you want these output in a sorted order, see L<perlfaq4>: ``How do I
+sort a hash (optionally by value instead of key)?''.
 
 =head2 How can I do approximate matching?
 
@@ -376,59 +486,42 @@ See the module String::Approx available from CPAN.
 
 =head2 How do I efficiently match many regular expressions at once?
 
-The following is super-inefficient:
-
-    while (<FH>) {
-        foreach $pat (@patterns) {
-            if ( /$pat/ ) {
-                # do something
-            }
-        }
-    }
-
-Instead, you either need to use one of the experimental Regexp extension
-modules from CPAN (which might well be overkill for your purposes),
-or else put together something like this, inspired from a routine
-in Jeffrey Friedl's book:
-
-    sub _bm_build {
-        my $condition = shift;
-        my @regexp = @_;  # this MUST not be local(); need my()
-        my $expr = join $condition => map { "m/\$regexp[$_]/o" } (0..$#regexp);
-        my $match_func = eval "sub { $expr }";
-        die if $@;  # propagate $@; this shouldn't happen!
-        return $match_func;
-    }
-
-    sub bm_and { _bm_build('&&', @_) }
-    sub bm_or  { _bm_build('||', @_) }
-
-    $f1 = bm_and qw{
-            xterm
-            (?i)window
-    };
+The following is extremely inefficient:
 
-    $f2 = bm_or qw{
-            \b[Ff]ree\b
-            \bBSD\B
-            (?i)sys(tem)?\s*[V5]\b
-    };
-
-    # feed me /etc/termcap, prolly
-    while ( <> ) {
-        print "1: $_" if &$f1;
-        print "2: $_" if &$f2;
+    # slow but obvious way
+    @popstates = qw(CO ON MI WI MN);
+    while (defined($line = <>)) {
+       for $state (@popstates) {
+           if ($line =~ /\b$state\b/i) {  
+               print $line;
+               last;
+           }
+       }
+    }                                        
+
+That's because Perl has to recompile all those patterns for each of
+the lines of the file.  As of the 5.005 release, there's a much better
+approach, one which makes use of the new C<qr//> operator:
+
+    # use spiffy new qr// operator, with /i flag even
+    use 5.005;
+    @popstates = qw(CO ON MI WI MN);
+    @poppats   = map { qr/\b$_\b/i } @popstates;
+    while (defined($line = <>)) {
+       for $patobj (@poppats) {
+           print $line if $line =~ /$patobj/;
+       }
     }
 
 =head2 Why don't word-boundary searches with C<\b> work for me?
 
-Two common misconceptions are that C<\b> is a synonym for C<\s+>, and
+Two common misconceptions are that C<\b> is a synonym for C<\s+> and
 that it's the edge between whitespace characters and non-whitespace
 characters.  Neither is correct.  C<\b> is the place between a C<\w>
 character and a C<\W> character (that is, C<\b> is the edge of a
 "word").  It's a zero-width assertion, just like C<^>, C<$>, and all
 the other anchors, so it doesn't consume any characters.  L<perlre>
-describes the behaviour of all the regexp metacharacters.
+describes the behavior of all the regex metacharacters.
 
 Here are examples of the incorrect application of C<\b>, with fixes:
 
@@ -449,26 +542,33 @@ not "this" or "island".
 
 =head2 Why does using $&, $`, or $' slow my program down?
 
-Because once Perl sees that you need one of these variables anywhere
-in the program, it has to provide them on each and every pattern
-match.  The same mechanism that handles these provides for the use of
-$1, $2, etc., so you pay the same price for each regexp that contains
-capturing parentheses. But if you never use $&, etc., in your script,
-then regexps I<without> capturing parentheses won't be penalized. So
-avoid $&, $', and $` if you can, but if you can't (and some algorithms
-really appreciate them), once you've used them once, use them at will,
-because you've already paid the price.
+Once Perl sees that you need one of these variables anywhere in
+the program, it provides them on each and every pattern match.
+The same mechanism that handles these provides for the use of $1, $2,
+etc., so you pay the same price for each regex that contains capturing
+parentheses.  If you never use $&, etc., in your script, then regexes
+I<without> capturing parentheses won't be penalized. So avoid $&, $',
+and $` 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?
 
-The notation C<\G> is used in a match or substitution in conjunction the
-C</g> modifier (and ignored if there's no C</g>) to anchor the regular
-expression to the point just past where the last match occurred, i.e. the
-pos() point.
+The notation C<\G> is used in a match or substitution in conjunction with
+the C</g> modifier to anchor the regular expression to the point just past
+where the last match occurred, i.e. the pos() point.  A failed match resets
+the position of C<\G> unless the C</c> modifier is in effect. C<\G> can be
+used in a match without the C</g> modifier; it acts the same (i.e. still
+anchors at the pos() point) but of course only matches once and does not
+update pos(), as non-C</g> expressions never do. C<\G> in an expression
+applied to a target string that has never been matched against a C</g>
+expression before or has had its pos() reset is functionally equivalent to
+C<\A>, which matches at the beginning of the string.
 
 For example, suppose you had a line of text quoted in standard mail
-and Usenet notation, (that is, with leading C<E<gt>> characters), and
-you want change each leading C<E<gt>> into a corresponding C<:>.  You
+and Usenet notation, (that is, with leading C<< > >> characters), and
+you want change each leading C<< > >> into a corresponding C<:>.  You
 could do so in this way:
 
      s/^(>+)/':' x length($1)/gem;
@@ -517,9 +617,9 @@ Of course, that could have been written as
       }
     }
 
-But then you lose the vertical alignment of the regular expressions.
+but then you lose the vertical alignment of the regular expressions.
 
-=head2 Are Perl regexps DFAs or NFAs?  Are they POSIX compliant?
+=head2 Are Perl regexes DFAs or NFAs?  Are they POSIX compliant?
 
 While it's true that Perl's regular expressions resemble the DFAs
 (deterministic finite automata) of the egrep(1) program, they are in
@@ -534,12 +634,10 @@ L<perlfaq2>).
 
 =head2 What's wrong with using grep or map in a void context?
 
-Strictly speaking, nothing.  Stylistically speaking, it's not a good
-way to write maintainable code.  That's because you're using these
-constructs not for their return values but rather for their
-side-effects, and side-effects can be mystifying.  There's no void
-grep() that's not better written as a C<for> (well, C<foreach>,
-technically) loop.
+Both grep and map build a return list, regardless of their context.
+This means you're making Perl go to the trouble of building up a
+return list that you then just ignore.  That's no way to treat a
+programming language, you insensitive scoundrel!
 
 =head2 How can I match strings with multibyte characters?
 
@@ -587,19 +685,48 @@ Or like this:
 
 Or like this:
 
-   die "sorry, Perl doesn't (yet) have Martian support )-:\n";
-
-In addition, a sample program which converts half-width to full-width
-katakana (in Shift-JIS or EUC encoding) is available from CPAN as
-
-=for Tom make it so
+    die "sorry, Perl doesn't (yet) have Martian support )-:\n";
 
 There are many double- (and multi-) byte encodings commonly used these
 days.  Some versions of these have 1-, 2-, 3-, and 4-byte characters,
 all mixed.
 
+=head2 How do I match a pattern that is supplied by the user?
+
+Well, if it's really a pattern, then just use
+
+    chomp($pattern = <STDIN>);
+    if ($line =~ /$pattern/) { }
+
+Alternatively, since you have no guarantee that your user entered
+a valid regular expression, trap the exception this way:
+
+    if (eval { $line =~ /$pattern/ }) { }
+
+If all you really want to search for a string, not a pattern,
+then you should either use the index() function, which is made for
+string searching, or if you can't be disabused of using a pattern
+match on a non-pattern, then be sure to use C<\Q>...C<\E>, documented
+in L<perlre>.
+
+    $pattern = <STDIN>;
+
+    open (FILE, $input) or die "Couldn't open input $input: $!; aborting";
+    while (<FILE>) {
+       print if /\Q$pattern\E/;
+    }
+    close FILE;
+
 =head1 AUTHOR AND COPYRIGHT
 
-Copyright (c) 1997 Tom Christiansen and Nathan Torkington.
-All rights reserved.  See L<perlfaq> for distribution information.
+Copyright (c) 1997-1999 Tom Christiansen and Nathan Torkington.
+All rights reserved.
+
+This documentation is free; you can redistribute it and/or modify it
+under the same terms as Perl itself.
 
+Irrespective of its distribution, all code examples in this file
+are hereby placed into the public domain.  You are permitted and
+encouraged to use this code in your own programs for fun
+or for profit as you see fit.  A simple comment in the code giving
+credit would be courteous but is not required.