P e r l d o c B r o w s e r
●
5 . 1 8 . 3
L a t e s t
5 . 4 0 . 0
5 . 3 8 . 2
5 . 3 8 . 1
5 . 3 8 . 0
5 . 3 6 . 3
5 . 3 6 . 2
5 . 3 6 . 1
5 . 3 6 . 0
5 . 3 4 . 3
5 . 3 4 . 2
5 . 3 4 . 1
5 . 3 4 . 0
5 . 3 2 . 1
5 . 3 2 . 0
5 . 3 0 . 3
5 . 3 0 . 2
5 . 3 0 . 1
5 . 3 0 . 0
5 . 2 8 . 3
5 . 2 8 . 2
5 . 2 8 . 1
5 . 2 8 . 0
5 . 2 6 . 3
5 . 2 6 . 2
5 . 2 6 . 1
5 . 2 6 . 0
5 . 2 4 . 4
5 . 2 4 . 3
5 . 2 4 . 2
5 . 2 4 . 1
5 . 2 4 . 0
5 . 2 2 . 4
5 . 2 2 . 3
5 . 2 2 . 2
5 . 2 2 . 1
5 . 2 2 . 0
5 . 2 0 . 3
5 . 2 0 . 2
5 . 2 0 . 1
5 . 2 0 . 0
5 . 1 8 . 4
5 . 1 8 . 3
5 . 1 8 . 2
5 . 1 8 . 1
5 . 1 8 . 0
5 . 1 6 . 3
5 . 1 6 . 2
5 . 1 6 . 1
5 . 1 6 . 0
5 . 1 4 . 4
5 . 1 4 . 3
5 . 1 4 . 2
5 . 1 4 . 1
5 . 1 4 . 0
5 . 1 2 . 5
5 . 1 2 . 4
5 . 1 2 . 3
5 . 1 2 . 2
5 . 1 2 . 1
5 . 1 2 . 0
5 . 1 0 . 1
5 . 1 0 . 0
5 . 8 . 9
5 . 8 . 8
5 . 8 . 7
5 . 8 . 6
5 . 8 . 5
5 . 8 . 4
5 . 8 . 3
5 . 8 . 2
5 . 8 . 1
5 . 8 . 0
5 . 6 . 2
5 . 6 . 1
5 . 6 . 0
5 . 0 0 5 _ 0 4
5 . 0 0 5 _ 0 3
5 . 0 0 5 _ 0 2
5 . 0 0 5 _ 0 1
5 . 0 0 5
●
D e v
b l e a d
5 . 4 1 . 2
5 . 4 1 . 1
5 . 4 0 . 0 - R C 2
5 . 4 0 . 0 - R C 1
5 . 3 9 . 1 0
5 . 3 9 . 9
5 . 3 9 . 8
5 . 3 9 . 6
5 . 3 9 . 5
5 . 3 9 . 4
5 . 3 9 . 3
5 . 3 9 . 2
5 . 3 9 . 1
5 . 3 7 . 1 1
5 . 3 7 . 1 0
5 . 3 7 . 9
5 . 3 7 . 8
5 . 3 7 . 7
5 . 3 7 . 6
5 . 3 7 . 5
5 . 3 7 . 4
5 . 3 7 . 3
5 . 3 7 . 2
5 . 3 7 . 1
5 . 3 7 . 0
●
D o c u m e n t a t i o n
P e r l
I n t r o
T u t o r i a l s
F A Q s
R e f e r e n c e
O p e r a t o r s
F u n c t i o n s
V a r i a b l e s
M o d u l e s
U t i l i t i e s
C o m m u n i t y
H i s t o r y
E x p a n d
p e r l f a q 6
( s o u r c e ,
C P A N )
Y o u a r e v i e w i n g t h e v e r s i o n o f t h i s d o c u m e n t a t i o n f r o m P e r l 5 . 1 8 . 3 .
V i e w t h e l a t e s t v e r s i o n
●
N A M E
●
D E S C R I P T I O N
●
H o w c a n I h o p e t o u s e r e g u l a r e x p r e s s i o n s w i t h o u t c r e a t i n g i l l e g i b l e a n d u n m a i n t a i n a b l e c o d e ?
●
I ' m h a v i n g t r o u b l e m a t c h i n g o v e r m o r e t h a n o n e l i n e . W h a t ' s w r o n g ?
●
H o w c a n I p u l l o u t l i n e s b e t w e e n t w o p a t t e r n s t h a t a r e t h e m s e l v e s o n d i f f e r e n t l i n e s ?
●
H o w d o I m a t c h X M L , H T M L , o r o t h e r n a s t y , u g l y t h i n g s w i t h a r e g e x ?
●
I p u t a r e g u l a r e x p r e s s i o n i n t o $ / b u t i t d i d n ' t w o r k . W h a t ' s w r o n g ?
●
H o w d o I s u b s t i t u t e c a s e - i n s e n s i t i v e l y o n t h e L H S w h i l e p r e s e r v i n g c a s e o n t h e R H S ?
●
H o w c a n I m a k e \ w m a t c h n a t i o n a l c h a r a c t e r s e t s ?
●
H o w c a n I m a t c h a l o c a l e - s m a r t v e r s i o n o f / [ a - z A - Z ] / ?
●
H o w c a n I q u o t e a v a r i a b l e t o u s e i n a r e g e x ?
●
W h a t i s / o r e a l l y f o r ?
●
H o w d o I u s e a r e g u l a r e x p r e s s i o n t o s t r i p C - s t y l e c o m m e n t s f r o m a f i l e ?
●
C a n I u s e P e r l r e g u l a r e x p r e s s i o n s t o m a t c h b a l a n c e d t e x t ?
●
W h a t d o e s i t m e a n t h a t r e g e x e s a r e g r e e d y ? H o w c a n I g e t a r o u n d i t ?
●
H o w d o I p r o c e s s e a c h w o r d o n e a c h l i n e ?
●
H o w c a n I p r i n t o u t a w o r d - f r e q u e n c y o r l i n e - f r e q u e n c y s u m m a r y ?
●
H o w c a n I d o a p p r o x i m a t e m a t c h i n g ?
●
H o w d o I e f f i c i e n t l y m a t c h m a n y r e g u l a r e x p r e s s i o n s a t o n c e ?
●
W h y d o n ' t w o r d - b o u n d a r y s e a r c h e s w i t h \ b w o r k f o r m e ?
●
W h y d o e s u s i n g $ & , $ ` , o r $ ' s l o w m y p r o g r a m d o w n ?
●
W h a t g o o d i s \ G i n a r e g u l a r e x p r e s s i o n ?
●
A r e P e r l r e g e x e s D F A s o r N F A s ? A r e t h e y P O S I X c o m p l i a n t ?
●
W h a t ' s w r o n g w i t h u s i n g g r e p i n a v o i d c o n t e x t ?
●
H o w c a n I m a t c h s t r i n g s w i t h m u l t i b y t e c h a r a c t e r s ?
●
H o w d o I m a t c h a r e g u l a r e x p r e s s i o n t h a t ' s i n a v a r i a b l e ?
●
A U T H O R A N D C O P Y R I G H T
# N A M E
p e r l f a q 6 - R e g u l a r E x p r e s s i o n s
# D E S C R I P T I O N
T h i s s e c t i o n i s s u r p r i s i n g l y s m a l l b e c a u s e t h e r e s t o f t h e F A Q i s l i t t e r e d w i t h a n s w e r s i n v o l v i n g r e g u l a r e x p r e s s i o n s . F o r e x a m p l e , d e c o d i n g a U R L a n d c h e c k i n g w h e t h e r s o m e t h i n g i s a n u m b e r c a n b e h a n d l e d w i t h r e g u l a r e x p r e s s i o n s , b u t t h o s e a n s w e r s a r e f o u n d e l s e w h e r e i n t h i s d o c u m e n t ( in p e r l f a q 9 : " H o w d o I d e c o d e o r c r e a t e t h o s e % - e n c o d i n g s o n t h e w e b " a n d p e r l f a q 4 : " H o w d o I d e t e r m i n e w h e t h e r a s c a l a r i s a n u m b e r / w h o l e / i n t e g e r / f l o a t " , t o b e p r e c i s e ) .
# H o w c a n I h o p e t o u s e r e g u l a r e x p r e s s i o n s w i t h o u t c r e a t i n g i l l e g i b l e a n d u n m a i n t a i n a b l e c o d e ?
T h r e e t e c h n i q u e s c a n m a k e r e g u l a r e x p r e s s i o n s m a i n t a i n a b l e a n d u n d e r s t a n d a b l e .
# C o m m e n t s O u t s i d e t h e R e g e x
D e s c r i b e w h a t y o u ' r e d o i n g a n d h o w y o u ' r e d o i n g i t , u s i n g n o r m a l P e r l c o m m e n t s .
# 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) /meg;
# C o m m e n t s I n s i d e t h e R e g e x
T h e / x
m o d i f i e r c a u s e s w h i t e s p a c e t o b e i g n o r e d i n a r e g e x p a t t e r n ( e x c e p t i n a c h a r a c t e r c l a s s a n d a f e w o t h e r p l a c e s ) , a n d a l s o a l l o w s y o u t o u s e n o r m a l c o m m e n t s t h e r e , t o o . A s y o u c a n i m a g i n e , w h i t e s p a c e a n d c o m m e n t s h e l p a l o t .
/ x
l e t s y o u t u r n t h i s :
s{<(?:[^>'"]*|".*?"|'.*?')+>}{}gs;
i n t o t h i s :
s{ < # opening angle bracket
(?: # Non-backreffing grouping paren
[^>'"] * # 0 or more things that are neither > nor ' nor "
| # or else
".*?" # a section between double quotes (stingy match)
| # or else
'.*?' # a section between single quotes (stingy match)
) + # all occurring one or more times
> # closing angle bracket
}{}gsx; # replace with nothing, i.e. delete
I t ' s s t i l l n o t q u i t e s o c l e a r a s p r o s e , b u t i t i s v e r y u s e f u l f o r d e s c r i b i n g t h e m e a n i n g o f e a c h p a r t o f t h e p a t t e r n .
# D i f f e r e n t D e l i m i t e r s
W h i l e w e n o r m a l l y t h i n k o f p a t t e r n s a s b e i n g d e l i m i t e d w i t h /
c h a r a c t e r s , t h e y c a n b e d e l i m i t e d b y a l m o s t a n y c h a r a c t e r . p e r l r e d e s c r i b e s t h i s . F o r e x a m p l e , t h e s / / /
a b o v e u s e s b r a c e s a s d e l i m i t e r s . S e l e c t i n g a n o t h e r d e l i m i t e r c a n a v o i d q u o t i n g t h e d e l i m i t e r w i t h i n t h e p a t t e r n :
s/\/usr\/local/\/usr\/share/g; # bad delimiter choice
s#/usr/local#/usr/share#g; # better
U s i n g l o g i c a l l y p a i r e d d e l i m i t e r s c a n b e e v e n m o r e r e a d a b l e :
s{/usr/local/}{/usr/share}g; # better still
# I ' m h a v i n g t r o u b l e m a t c h i n g o v e r m o r e t h a n o n e l i n e . W h a t ' s w r o n g ?
E i t h e r y o u d o n ' t h a v e m o r e t h a n o n e l i n e i n t h e s t r i n g y o u ' r e l o o k i n g a t ( p r o b a b l y ) , o r e l s e y o u a r e n ' t u s i n g t h e c o r r e c t m o d i f i e r ( s ) o n y o u r p a t t e r n ( p o s s i b l y ) .
T h e r e a r e m a n y w a y s t o g e t m u l t i l i n e d a t a i n t o a s t r i n g . I f y o u w a n t i t t o h a p p e n a u t o m a t i c a l l y w h i l e r e a d i n g i n p u t , y o u ' l l w a n t t o s e t $ / ( p r o b a b l y t o ' ' f o r p a r a g r a p h s o r u n d e f
f o r t h e w h o l e f i l e ) t o a l l o w y o u t o r e a d m o r e t h a n o n e l i n e a t a t i m e .
R e a d p e r l r e t o h e l p y o u d e c i d e w h i c h o f / s
a n d / m
( o r b o t h ) y o u m i g h t w a n t t o u s e : / s
a l l o w s d o t t o i n c l u d e n e w l i n e , a n d / m
a l l o w s c a r e t a n d d o l l a r t o m a t c h n e x t t o a n e w l i n e , n o t j u s t a t t h e e n d o f t h e s t r i n g . Y o u d o n e e d t o m a k e s u r e t h a t y o u ' v e a c t u a l l y g o t a m u l t i l i n e s t r i n g i n t h e r e .
F o r e x a m p l e , t h i s p r o g r a m d e t e c t s d u p l i c a t e w o r d s , e v e n w h e n t h e y s p a n l i n e b r e a k s ( b u t n o t p a r a g r a p h o n e s ) . F o r t h i s e x a m p l e , w e d o n ' t n e e d / s
b e c a u s e w e a r e n ' t u s i n g d o t i n a r e g u l a r e x p r e s s i o n t h a t w e w a n t t o c r o s s l i n e b o u n d a r i e s . N e i t h e r d o w e n e e d / m
b e c a u s e w e d o n ' t w a n t c a r e t o r d o l l a r t o m a t c h a t a n y p o i n t i n s i d e t h e r e c o r d n e x t t o n e w l i n e s . B u t i t ' s i m p e r a t i v e t h a t $ / b e s e t t o s o m e t h i n g o t h e r t h a n t h e d e f a u l t , o r e l s e w e w o n ' t a c t u a l l y e v e r h a v e a m u l t i l i n e r e c o r d r e a d i n .
$/ = ''; # read in whole paragraph, not just one line
while ( <> ) {
while ( /\b([\w'-]+)(\s+\g1)+\b/gi ) { # word starts alpha
print "Duplicate $1 at paragraph $.\n";
}
}
H e r e ' s s o m e c o d e t h a t f i n d s s e n t e n c e s t h a t b e g i n w i t h " F r o m " ( w h i c h w o u l d b e m a n g l e d b y m a n y m a i l e r s ) :
$/ = ''; # read in whole paragraph, not just one line
while ( <> ) {
while ( /^From /gm ) { # /m makes ^ match next to \n
print "leading from in paragraph $.\n";
}
}
H e r e ' s c o d e t h a t f i n d s e v e r y t h i n g b e t w e e n S T A R T a n d E N D i n a p a r a g r a p h :
undef $/; # read in whole file, not just one line or paragraph
while ( <> ) {
while ( /START(.*?)END/sgm ) { # /s makes . cross line boundaries
print "$1\n";
}
}
# H o w c a n I p u l l o u t l i n e s b e t w e e n t w o p a t t e r n s t h a t a r e t h e m s e l v e s o n d i f f e r e n t l i n e s ?
Y o u c a n u s e P e r l ' s s o m e w h a t e x o t i c . .
o p e r a t o r ( d o c u m e n t e d i n p e r l o p ) :
perl -ne 'print if /START/ .. /END/' file1 file2 ...
I f y o u w a n t e d t e x t a n d n o t l i n e s , y o u w o u l d u s e
perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...
B u t i f y o u w a n t n e s t e d o c c u r r e n c e s o f S T A R T
t h r o u g h E N D
, y o u ' l l r u n u p a g a i n s t t h e p r o b l e m d e s c r i b e d i n t h e q u e s t i o n i n t h i s s e c t i o n o n m a t c h i n g b a l a n c e d t e x t .
H e r e ' s a n o t h e r e x a m p l e o f u s i n g .
.
:
while (<>) {
my $in_header = 1 .. /^$/;
my $in_body = /^$/ .. eof;
# now choose between them
} continue {
$. = 0 if eof; # fix $.
}
# H o w d o I m a t c h X M L , H T M L , o r o t h e r n a s t y , u g l y t h i n g s w i t h a r e g e x ?
D o n o t u s e r e g e x e s . U s e a m o d u l e a n d f o r g e t a b o u t t h e r e g u l a r e x p r e s s i o n s . T h e X M L : : L i b X M L , H T M L : : T o k e P a r s e r a n d H T M L : : T r e e B u i l d e r m o d u l e s a r e g o o d s t a r t s , a l t h o u g h e a c h n a m e s p a c e h a s o t h e r p a r s i n g m o d u l e s s p e c i a l i z e d f o r c e r t a i n t a s k s a n d d i f f e r e n t w a y s o f d o i n g i t . S t a r t a t C P A N S e a r c h ( h t t p : / / m e t a c p a n . o r g / ) a n d w o n d e r a t a l l t h e w o r k p e o p l e h a v e d o n e f o r y o u a l r e a d y ! : )
# I p u t a r e g u l a r e x p r e s s i o n i n t o $ / b u t i t d i d n ' t w o r k . W h a t ' s w r o n g ?
$ / h a s t o b e a s t r i n g . Y o u c a n u s e t h e s e e x a m p l e s i f y o u r e a l l y n e e d t o d o t h i s .
I f y o u h a v e F i l e : : S t r e a m , t h i s i s e a s y .
use File::Stream;
my $stream = File::Stream->new(
$filehandle,
separator => qr/\s*,\s*/,
);
print "$_\n" while <$stream>;
I f y o u d o n ' t h a v e F i l e : : S t r e a m , y o u h a v e t o d o a l i t t l e m o r e w o r k .
Y o u c a n u s e t h e f o u r - a r g u m e n t f o r m o f s y s r e a d t o c o n t i n u a l l y a d d t o a b u f f e r . A f t e r y o u a d d t o t h e b u f f e r , y o u c h e c k i f y o u h a v e a c o m p l e t e l i n e ( u s i n g y o u r r e g u l a r e x p r e s s i o n ) .
local $_ = "";
while( sysread FH, $_, 8192, length ) {
while( s/^((?s).*?)your_pattern// ) {
my $record = $1;
# do stuff here.
}
}
Y o u c a n d o t h e s a m e t h i n g w i t h f o r e a c h a n d a m a t c h u s i n g t h e c f l a g a n d t h e \ G a n c h o r , i f y o u d o n o t m i n d y o u r e n t i r e f i l e b e i n g i n m e m o r y a t t h e e n d .
local $_ = "";
while( sysread FH, $_, 8192, length ) {
foreach my $record ( m/\G((?s).*?)your_pattern/gc ) {
# do stuff here.
}
substr( $_, 0, pos ) = "" if pos;
}
# H o w d o I s u b s t i t u t e c a s e - i n s e n s i t i v e l y o n t h e L H S w h i l e p r e s e r v i n g c a s e o n t h e R H S ?
H e r e ' s a l o v e l y P e r l i s h s o l u t i o n b y L a r r y R o s l e r . I t e x p l o i t s p r o p e r t i e s o f b i t w i s e x o r o n A S C I I s t r i n g s .
$_= "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;
A n d h e r e i t i s a s a s u b r o u t i n e , m o d e l e d a f t e r t h e a b o v e :
sub preserve_case {
my ($old, $new) = @_;
my $mask = uc $old ^ $old;
uc $new | $mask .
substr($mask, -1) x (length($new) - length($old))
}
$string = "this is a TEsT case";
$string =~ s/(test)/preserve_case($1, "success")/egi;
print "$string\n";
T h i s p r i n t s :
this is a SUcCESS case
A s a n a l t e r n a t i v e , t o k e e p t h e c a s e o f t h e r e p l a c e m e n t w o r d i f i t i s l o n g e r t h a n t h e o r i g i n a l , y o u c a n u s e t h i s c o d e , b y J e f f P i n y a n :
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);
}
T h i s c h a n g e s t h e s e n t e n c e t o " t h i s i s a S U c C e s s c a s e . "
J u s t t o s h o w t h a t C p r o g r a m m e r s c a n w r i t e C i n a n y p r o g r a m m i n g l a n g u a g e , i f y o u p r e f e r a m o r e C - l i k e s o l u t i o n , t h e f o l l o w i n g s c r i p t m a k e s t h e s u b s t i t u t i o n h a v e t h e s a m e c a s e , l e t t e r b y l e t t e r , a s t h e o r i g i n a l . ( I t a l s o h a p p e n s t o r u n a b o u t 2 4 0 % s l o w e r t h a n t h e P e r l i s h s o l u t i o n r u n s . ) I f t h e s u b s t i t u t i o n h a s m o r e c h a r a c t e r s t h a n t h e s t r i n g b e i n g s u b s t i t u t e d , t h e c a s e o f t h e l a s t c h a r a c t e r i s u s e d f o r t h e r e s t o f t h e s u b s t i t u t i o n .
# Original by Nathan Torkington, massaged by Jeffrey Friedl
#
sub preserve_case
{
my ($old, $new) = @_;
my $state = 0; # 0 = no change; 1 = lc; 2 = uc
my ($i, $oldlen, $newlen, $c) = (0, length($old), length($new));
my $len = $oldlen < $newlen ? $oldlen : $newlen;
for ($i = 0; $i < $len; $i++) {
if ($c = substr($old, $i, 1), $c =~ /[\W\d_]/) {
$state = 0;
} elsif (lc $c eq $c) {
substr($new, $i, 1) = lc(substr($new, $i, 1));
$state = 1;
} else {
substr($new, $i, 1) = uc(substr($new, $i, 1));
$state = 2;
}
}
# finish up with any remaining new (for when new is longer than old)
if ($newlen > $oldlen) {
if ($state == 1) {
substr($new, $oldlen) = lc(substr($new, $oldlen));
} elsif ($state == 2) {
substr($new, $oldlen) = uc(substr($new, $oldlen));
}
}
return $new;
}
# H o w c a n I m a k e \ w
m a t c h n a t i o n a l c h a r a c t e r s e t s ?
P u t u s e l o c a l e ;
i n y o u r s c r i p t . T h e \ w c h a r a c t e r c l a s s i s t a k e n f r o m t h e c u r r e n t l o c a l e .
S e e p e r l l o c a l e f o r d e t a i l s .
# H o w c a n I m a t c h a l o c a l e - s m a r t v e r s i o n o f / [ a - z A - Z ] /
?
Y o u c a n u s e t h e P O S I X c h a r a c t e r c l a s s s y n t a x / [ [ : a l p h a : ] ] /
d o c u m e n t e d i n p e r l r e .
N o m a t t e r w h i c h l o c a l e y o u a r e i n , t h e a l p h a b e t i c c h a r a c t e r s a r e t h e c h a r a c t e r s i n \ w w i t h o u t t h e d i g i t s a n d t h e u n d e r s c o r e . A s a r e g e x , t h a t l o o k s l i k e / [ ^ \ W \ d
_ ] /
. I t s c o m p l e m e n t , t h e n o n - a l p h a b e t i c s , i s t h e n e v e r y t h i n g i n \ W a l o n g w i t h t h e d i g i t s a n d t h e u n d e r s c o r e , o r / [ \ W \ d _ ] /
.
# H o w c a n I q u o t e a v a r i a b l e t o u s e i n a r e g e x ?
T h e P e r l p a r s e r w i l l e x p a n d $ v a r i a b l e a n d @ v a r i a b l e r e f e r e n c e s i n r e g u l a r e x p r e s s i o n s u n l e s s t h e d e l i m i t e r i s a s i n g l e q u o t e . R e m e m b e r , t o o , t h a t t h e r i g h t - h a n d s i d e o f a s / / /
s u b s t i t u t i o n i s c o n s i d e r e d a d o u b l e - q u o t e d s t r i n g ( s e e p e r l o p f o r m o r e d e t a i l s ) . R e m e m b e r a l s o t h a t a n y r e g e x s p e c i a l c h a r a c t e r s w i l l b e a c t e d o n u n l e s s y o u p r e c e d e t h e s u b s t i t u t i o n w i t h \ Q . H e r e ' s a n e x a m p l e :
$string = "Placido P. Octopus";
$regex = "P.";
$string =~ s/$regex/Polyp/;
# $string is now "Polypacido P. Octopus"
B e c a u s e .
i s s p e c i a l i n r e g u l a r e x p r e s s i o n s , a n d c a n m a t c h a n y s i n g l e c h a r a c t e r , t h e r e g e x P .
h e r e h a s m a t c h e d t h e < P l > i n t h e o r i g i n a l s t r i n g .
T o e s c a p e t h e s p e c i a l m e a n i n g o f .
, w e u s e \ Q
:
$string = "Placido P. Octopus";
$regex = "P.";
$string =~ s/\Q$regex/Polyp/;
# $string is now "Placido Polyp Octopus"
T h e u s e o f \ Q
c a u s e s t h e < . > i n t h e r e g e x t o b e t r e a t e d a s a r e g u l a r c h a r a c t e r , s o t h a t P .
m a t c h e s a P
f o l l o w e d b y a d o t .
# W h a t i s / o
r e a l l y f o r ?
( c o n t r i b u t e d b y b r i a n d f o y )
T h e / o
o p t i o n f o r r e g u l a r e x p r e s s i o n s ( d o c u m e n t e d i n p e r l o p a n d p e r l r e r e f ) t e l l s P e r l t o c o m p i l e t h e r e g u l a r e x p r e s s i o n o n l y o n c e . T h i s i s o n l y u s e f u l w h e n t h e p a t t e r n c o n t a i n s a v a r i a b l e . P e r l s 5 . 6 a n d l a t e r h a n d l e t h i s a u t o m a t i c a l l y i f t h e p a t t e r n d o e s n o t c h a n g e .
S i n c e t h e m a t c h o p e r a t o r m / /
, t h e s u b s t i t u t i o n o p e r a t o r s / / /
, a n d t h e r e g u l a r e x p r e s s i o n q u o t i n g o p e r a t o r q r / /
a r e d o u b l e - q u o t i s h c o n s t r u c t s , y o u c a n i n t e r p o l a t e v a r i a b l e s i n t o t h e p a t t e r n . S e e t h e a n s w e r t o " H o w c a n I q u o t e a v a r i a b l e t o u s e i n a r e g e x ? " f o r m o r e d e t a i l s .
T h i s e x a m p l e t a k e s a r e g u l a r e x p r e s s i o n f r o m t h e a r g u m e n t l i s t a n d p r i n t s t h e l i n e s o f i n p u t t h a t m a t c h i t :
my $pattern = shift @ARGV;
while( <> ) {
print if m/$pattern/;
}
V e r s i o n s o f P e r l p r i o r t o 5 . 6 w o u l d r e c o m p i l e t h e r e g u l a r e x p r e s s i o n f o r e a c h i t e r a t i o n , e v e n i f $ p a t t e r n
h a d n o t c h a n g e d . T h e /
o
w o u l d p r e v e n t t h i s b y t e l l i n g P e r l t o c o m p i l e t h e p a t t e r n t h e f i r s t t i m e , t h e n r e u s e t h a t f o r s u b s e q u e n t i t e r a t i o n s :
my $pattern = shift @ARGV;
while( <> ) {
print if m/$pattern/o; # useful for Perl < 5.6
}
I n v e r s i o n s 5 . 6 a n d l a t e r , P e r l w o n ' t r e c o m p i l e t h e r e g u l a r e x p r e s s i o n i f t h e v a r i a b l e h a s n ' t c h a n g e d , s o y o u p r o b a b l y d o n ' t n e e d t h e / o
o p t i o n . I t d o e s n ' t h u r t , b u t i t d o e s n ' t h e l p e i t h e r . I f y o u w a n t a n y v e r s i o n o f P e r l t o c o m p i l e t h e r e g u l a r e x p r e s s i o n o n l y o n c e e v e n i f t h e v a r i a b l e c h a n g e s ( t h u s , o n l y u s i n g i t s i n i t i a l v a l u e ) , y o u s t i l l n e e d t h e /
o
.
Y o u c a n w a t c h P e r l ' s r e g u l a r e x p r e s s i o n e n g i n e a t w o r k t o v e r i f y f o r y o u r s e l f i f P e r l i s r e c o m p i l i n g a r e g u l a r e x p r e s s i o n . T h e u
s e r e ' d e b u g '
p r a g m a ( c o m e s w i t h P e r l 5 . 0 0 5 a n d l a t e r ) s h o w s t h e d e t a i l s . W i t h P e r l s b e f o r e 5 . 6 , y o u s h o u l d s e e re
r e p o r t i n g t h a t i t s c o m p i l i n g t h e r e g u l a r e x p r e s s i o n o n e a c h i t e r a t i o n . W i t h P e r l 5 . 6 o r l a t e r , y o u s h o u l d o n l y s e e re
r e p o r t t h a t f o r t h e f i r s t i t e r a t i o n .
use re 'debug';
my $regex = 'Perl';
foreach ( qw(Perl Java Ruby Python) ) {
print STDERR "-" x 73, "\n";
print STDERR "Trying $_...\n";
print STDERR "\t$_ is good!\n" if m/$regex/;
}
W h i l e t h i s a c t u a l l y c a n b e d o n e , i t ' s m u c h h a r d e r t h a n y o u ' d t h i n k . F o r e x a m p l e , t h i s o n e - l i n e r
perl -0777 -pe 's{/\*.*?\*/}{}gs' foo.c
w i l l w o r k i n m a n y b u t n o t a l l c a s e s . Y o u s e e , i t ' s t o o s i m p l e - m i n d e d f o r c e r t a i n k i n d s o f C p r o g r a m s , i n p a r t i c u l a r , t h o s e w i t h w h a t a p p e a r t o b e c o m m e n t s i n q u o t e d s t r i n g s . F o r t h a t , y o u ' d n e e d s o m e t h i n g l i k e t h i s , c r e a t e d b y J e f f r e y F r i e d l a n d l a t e r m o d i f i e d b y F r e d C u r t i s .
$/ = undef;
$_ = <>;
s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $2 ? $2 : ""#gse;
print;
T h i s c o u l d , o f c o u r s e , b e m o r e l e g i b l y w r i t t e n w i t h t h e / x
m o d i f i e r , a d d i n g w h i t e s p a c e a n d c o m m e n t s . H e r e i t i s e x p a n d e d , c o u r t e s y o f F r e d C u r t i s .
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
)
}{defined $2 ? $2 : ""}gxse;
A s l i g h t m o d i f i c a t i o n a l s o r e m o v e s C + + c o m m e n t s , p o s s i b l y s p a n n i n g m u l t i p l e l i n e s u s i n g a c o n t i n u a t i o n c h a r a c t e r :
s#/\*[^*]*\*+([^/*][^*]*\*+)*/|//([^\\]|[^\n][\n]?)*?\n|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $3 ? $3 : ""#gse;
# C a n I u s e P e r l r e g u l a r e x p r e s s i o n s t o m a t c h b a l a n c e d t e x t ?
( c o n t r i b u t e d b y b r i a n d f o y )
Y o u r f i r s t t r y s h o u l d p r o b a b l y b e t h e T e x t : : B a l a n c e d m o d u l e , w h i c h i s i n t h e P e r l s t a n d a r d l i b r a r y s i n c e P e r l 5 . 8 . I t h a s a v a r i e t y o f f u n c t i o n s t o d e a l w i t h t r i c k y t e x t . T h e R e g e x p : : C o m m o n m o d u l e c a n a l s o h e l p b y p r o v i d i n g c a n n e d p a t t e r n s y o u c a n u s e .
A s o f P e r l 5 . 1 0 , y o u c a n m a t c h b a l a n c e d t e x t w i t h r e g u l a r e x p r e s s i o n s u s i n g r e c u r s i v e p a t t e r n s . B e f o r e P e r l 5 . 1 0 , y o u h a d t o r e s o r t t o v a r i o u s t r i c k s s u c h a s u s i n g P e r l c o d e i n ( ?? { } )
s e q u e n c e s .
H e r e ' s a n e x a m p l e u s i n g a r e c u r s i v e r e g u l a r e x p r e s s i o n . T h e g o a l i s t o c a p t u r e a l l o f t h e t e x t w i t h i n a n g l e b r a c k e t s , i n c l u d i n g t h e t e x t i n n e s t e d a n g l e b r a c k e t s . T h i s s a m p l e t e x t h a s t w o " m a j o r " g r o u p s : a g r o u p w i t h o n e l e v e l o f n e s t i n g a n d a g r o u p w i t h t w o l e v e l s o f n e s t i n g . T h e r e a r e f i v e t o t a l g r o u p s i n a n g l e b r a c k e t s :
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
T h e r e g u l a r e x p r e s s i o n t o m a t c h t h e b a l a n c e d t e x t u s e s t w o n e w ( t o P e r l 5 . 1 0 ) r e g u l a r e x p r e s s i o n f e a t u r e s . T h e s e a r e c o v e r e d i n p e r l r e a n d t h i s e x a m p l e i s a m o d i f i e d v e r s i o n o f o n e i n t h a t d o c u m e n t a t i o n .
F i r s t , a d d i n g t h e n e w p o s s e s s i v e +
t o a n y q u a n t i f i e r f i n d s t h e l o n g e s t m a t c h a n d d o e s n o t b a c k t r a c k . T h a t ' s i m p o r t a n t s i n c e y o u w a n t t o h a n d l e a n y a n g l e b r a c k e t s t h r o u g h t h e r e c u r s i o n , n o t b a c k t r a c k i n g . T h e g r o u p [ ^ < > ] + +
f i n d s o n e o r m o r e n o n - a n g l e b r a c k e t s w i t h o u t b a c k t r a c k i n g .
S e c o n d , t h e n e w ( ? P A R N O )
r e f e r s t o t h e s u b - p a t t e r n i n t h e p a r t i c u l a r c a p t u r e g r o u p g i v e n b y P A R N
O
. I n t h e f o l l o w i n g r e g e x , t h e f i r s t c a p t u r e g r o u p f i n d s ( a n d r e m e m b e r s ) t h e b a l a n c e d t e x t , a n d y o u n e e d t h a t s a m e p a t t e r n w i t h i n t h e f i r s t b u f f e r t o g e t p a s t t h e n e s t e d t e x t . T h a t ' s t h e r e c u r s i v e p a r t . T h e ( ? 1 )
u s e s t h e p a t t e r n i n t h e o u t e r c a p t u r e g r o u p a s a n i n d e p e n d e n t p a r t o f t h e r e g e x .
P u t t i n g i t a l l t o g e t h e r , y o u h a v e :
#!/usr/local/bin/perl5.10.0
my $string =<<"HERE";
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
HERE
my @groups = $string =~ m/
( # start of capture group 1
< # match an opening angle bracket
(?:
[^<>]++ # one or more non angle brackets, non backtracking
|
(?1) # found < or >, so recurse to capture group 1
)*
> # match a closing angle bracket
) # end of capture group 1
/xg;
$" = "\n\t";
print "Found:\n\t@groups\n";
T h e o u t p u t s h o w s t h a t P e r l f o u n d t h e t w o m a j o r g r o u p s :
Found:
<brackets in <nested brackets> >
<another group <nested once <nested twice> > >
W i t h a l i t t l e e x t r a w o r k , y o u c a n g e t t h e a l l o f t h e g r o u p s i n a n g l e b r a c k e t s e v e n i f t h e y a r e i n o t h e r a n g l e b r a c k e t s t o o . E a c h t i m e y o u g e t a b a l a n c e d m a t c h , r e m o v e i t s o u t e r d e l i m i t e r ( t h a t ' s t h e o n e y o u j u s t m a t c h e d s o d o n ' t m a t c h i t a g a i n ) a n d a d d i t t o a q u e u e o f s t r i n g s t o p r o c e s s . K e e p d o i n g t h a t u n t i l y o u g e t n o m a t c h e s :
#!/usr/local/bin/perl5.10.0
my @queue =<<"HERE";
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
HERE
my $regex = qr/
( # start of bracket 1
< # match an opening angle bracket
(?:
[^<>]++ # one or more non angle brackets, non backtracking
|
(?1) # recurse to bracket 1
)*
> # match a closing angle bracket
) # end of bracket 1
/x;
$" = "\n\t";
while( @queue ) {
my $string = shift @queue;
my @groups = $string =~ m/$regex/g;
print "Found:\n\t@groups\n\n" if @groups;
unshift @queue, map { s/^<//; s/>$//; $_ } @groups;
}
T h e o u t p u t s h o w s a l l o f t h e g r o u p s . T h e o u t e r m o s t m a t c h e s s h o w u p f i r s t a n d t h e n e s t e d m a t c h e s s o u p l a t e r :
Found:
<brackets in <nested brackets> >
<another group <nested once <nested twice> > >
Found:
<nested brackets>
Found:
<nested once <nested twice> >
Found:
<nested twice>
# W h a t d o e s i t m e a n t h a t r e g e x e s a r e g r e e d y ? H o w c a n I g e t a r o u n d i t ?
M o s t p e o p l e m e a n t h a t g r e e d y r e g e x e s m a t c h a s m u c h a s t h e y c a n . T e c h n i c a l l y s p e a k i n g , i t ' s a c t u a l l y t h e q u a n t i f i e r s ( ?
, *
, +
, { }
) t h a t a r e g r e e d y r a t h e r t h a n t h e w h o l e p a t t e r n ; P e r l p r e f e r s l o c a l g r e e d a n d i m m e d i a t e g r a t i f i c a t i o n t o o v e r a l l g r e e d . T o g e t n o n - g r e e d y v e r s i o n s o f t h e s a m e q u a n t i f i e r s , u s e ( ??
, * ?
, + ?
, { } ?
) .
A n e x a m p l e :
my $s1 = my $s2 = "I am very very cold";
$s1 =~ s/ve.*y //; # I am cold
$s2 =~ s/ve.*?y //; # I am very cold
N o t i c e h o w t h e s e c o n d s u b s t i t u t i o n s t o p p e d m a t c h i n g a s s o o n a s i t e n c o u n t e r e d " y " . T h e * ?
q u a n t i f i e r e f f e c t i v e l y t e l l s t h e r e g u l a r e x p r e s s i o n e n g i n e t o f i n d a m a t c h a s q u i c k l y a s p o s s i b l e a n d p a s s c o n t r o l o n t o w h a t e v e r i s n e x t i n l i n e , a s y o u w o u l d i f y o u w e r e p l a y i n g h o t p o t a t o .
# H o w d o I p r o c e s s e a c h w o r d o n e a c h l i n e ?
U s e t h e s p l i t f u n c t i o n :
while (<>) {
foreach my $word ( split ) {
# do something with $word here
}
}
N o t e t h a t t h i s i s n ' t r e a l l y a w o r d i n t h e E n g l i s h s e n s e ; i t ' s j u s t c h u n k s o f c o n s e c u t i v e n o n - w h i t e s p a c e c h a r a c t e r s .
T o w o r k w i t h o n l y a l p h a n u m e r i c s e q u e n c e s ( i n c l u d i n g u n d e r s c o r e s ) , y o u m i g h t c o n s i d e r
while (<>) {
foreach $word (m/(\w+)/g) {
# do something with $word here
}
}
# H o w c a n I p r i n t o u t a w o r d - f r e q u e n c y o r l i n e - f r e q u e n c y s u m m a r y ?
T o d o t h i s , y o u h a v e t o p a r s e o u t e a c h w o r d i n t h e i n p u t s t r e a m . W e ' l l p r e t e n d t h a t b y w o r d y o u m e a n c h u n k o f a l p h a b e t i c s , h y p h e n s , o r a p o s t r o p h e s , r a t h e r t h a n t h e n o n - w h i t e s p a c e c h u n k i d e a o f a w o r d g i v e n i n t h e p r e v i o u s q u e s t i o n :
my (%seen);
while (<>) {
while ( /(\b[^\W_\d][\w'-]+\b)/g ) { # misses "`sheep'"
$seen{$1}++;
}
}
while ( my ($word, $count) = each %seen ) {
print "$count $word\n";
}
I f y o u w a n t e d t o d o t h e s a m e t h i n g f o r l i n e s , y o u w o u l d n ' t n e e d a r e g u l a r e x p r e s s i o n :
my (%seen);
while (<>) {
$seen{$_}++;
}
while ( my ($line, $count) = each %seen ) {
print "$count $line";
}
I f y o u w a n t t h e s e o u t p u t i n a s o r t e d o r d e r , s e e p e r l f a q 4 : " H o w d o I s o r t a h a s h ( o p t i o n a l l y b y v a l u e i n s t e a d o f k e y ) ? " .
# H o w c a n I d o a p p r o x i m a t e m a t c h i n g ?
S e e t h e m o d u l e S t r i n g : : A p p r o x a v a i l a b l e f r o m C P A N .
# H o w d o I e f f i c i e n t l y m a t c h m a n y r e g u l a r e x p r e s s i o n s a t o n c e ?
( c o n t r i b u t e d b y b r i a n d f o y )
I f y o u h a v e P e r l 5 . 1 0 o r l a t e r , t h i s i s a l m o s t t r i v i a l . Y o u j u s t s m a r t m a t c h a g a i n s t a n a r r a y o f r e g u l a r e x p r e s s i o n o b j e c t s :
my @patterns = ( qr/Fr.d/, qr/B.rn.y/, qr/W.lm./ );
if( $string ~~ @patterns ) {
...
};
T h e s m a r t m a t c h s t o p s w h e n i t f i n d s a m a t c h , s o i t d o e s n ' t h a v e t o t r y e v e r y e x p r e s s i o n .
E a r l i e r t h a n P e r l 5 . 1 0 , y o u h a v e a b i t o f w o r k t o d o . Y o u w a n t t o a v o i d c o m p i l i n g a r e g u l a r e x p r e s s i o n e v e r y t i m e y o u w a n t t o m a t c h i t . I n t h i s e x a m p l e , p e r l m u s t r e c o m p i l e t h e r e g u l a r e x p r e s s i o n f o r e v e r y i t e r a t i o n o f t h e f
o r e a c h
l o o p s i n c e i t h a s n o w a y t o k n o w w h a t $ p a t t e r n
w i l l b e :
my @patterns = qw( foo bar baz );
LINE: while( <DATA> ) {
foreach $pattern ( @patterns ) {
if( /\b$pattern\b/i ) {
print;
next LINE;
}
}
}
T h e q r / /
o p e r a t o r s h o w e d u p i n p e r l 5 . 0 0 5 . I t c o m p i l e s a r e g u l a r e x p r e s s i o n , b u t d o e s n ' t a p p l y i t . W h e n y o u u s e t h e p r e - c o m p i l e d v e r s i o n o f t h e r e g e x , p e r l d o e s l e s s w o r k . I n t h i s e x a m p l e , I i n s e r t e d a m a p
t o t u r n e a c h p a t t e r n i n t o i t s p r e - c o m p i l e d f o r m . T h e r e s t o f t h e s c r i p t i s t h e s a m e , b u t f a s t e r :
my @patterns = map { qr/\b$_\b/i } qw( foo bar baz );
LINE: while( <> ) {
foreach $pattern ( @patterns ) {
if( /$pattern/ ) {
print;
next LINE;
}
}
}
I n s o m e c a s e s , y o u m a y b e a b l e t o m a k e s e v e r a l p a t t e r n s i n t o a s i n g l e r e g u l a r e x p r e s s i o n . B e w a r e o f s i t u a t i o n s t h a t r e q u i r e b a c k t r a c k i n g t h o u g h .
my $regex = join '|', qw( foo bar baz );
LINE: while( <> ) {
print if /\b(?:$regex)\b/i;
}
F o r m o r e d e t a i l s o n r e g u l a r e x p r e s s i o n e f f i c i e n c y , s e e M a s t e r i n g R e g u l a r E x p r e s s i o n s b y J e f f r e y F r i e d l . H e e x p l a i n s h o w t h e r e g u l a r e x p r e s s i o n s e n g i n e w o r k s a n d w h y s o m e p a t t e r n s a r e s u r p r i s i n g l y i n e f f i c i e n t . O n c e y o u u n d e r s t a n d h o w p e r l a p p l i e s r e g u l a r e x p r e s s i o n s , y o u c a n t u n e t h e m f o r i n d i v i d u a l s i t u a t i o n s .
# W h y d o n ' t w o r d - b o u n d a r y s e a r c h e s w i t h \ b
w o r k f o r m e ?
( c o n t r i b u t e d b y b r i a n d f o y )
E n s u r e t h a t y o u k n o w w h a t \ b r e a l l y d o e s : i t ' s t h e b o u n d a r y b e t w e e n a w o r d c h a r a c t e r , \ w , a n d s o m e t h i n g t h a t i s n ' t a w o r d c h a r a c t e r . T h a t t h i n g t h a t i s n ' t a w o r d c h a r a c t e r m i g h t b e \ W , b u t i t c a n a l s o b e t h e s t a r t o r e n d o f t h e s t r i n g .
I t ' s n o t ( n o t ! ) t h e b o u n d a r y b e t w e e n w h i t e s p a c e a n d n o n - w h i t e s p a c e , a n d i t ' s n o t t h e s t u f f b e t w e e n w o r d s w e u s e t o c r e a t e s e n t e n c e s .
I n r e g e x s p e a k , a w o r d b o u n d a r y ( \ b ) i s a " z e r o w i d t h a s s e r t i o n " , m e a n i n g t h a t i t d o e s n ' t r e p r e s e n t a c h a r a c t e r i n t h e s t r i n g , b u t a c o n d i t i o n a t a c e r t a i n p o s i t i o n .
F o r t h e r e g u l a r e x p r e s s i o n , / \ b P e r l \ b / , t h e r e h a s t o b e a w o r d b o u n d a r y b e f o r e t h e " P " a n d a f t e r t h e " l " . A s l o n g a s s o m e t h i n g o t h e r t h a n a w o r d c h a r a c t e r p r e c e d e s t h e " P " a n d s u c c e e d s t h e " l " , t h e p a t t e r n w i l l m a t c h . T h e s e s t r i n g s m a t c h / \ b P e r l \ b / .
"Perl" # no word char before P or after l
"Perl " # same as previous (space is not a word char)
"'Perl'" # the ' char is not a word char
"Perl's" # no word char before P, non-word char after "l"
T h e s e s t r i n g s d o n o t m a t c h / \ b P e r l \ b / .
"Perl_" # _ is a word char!
"Perler" # no word char before P, but one after l
Y o u d o n ' t h a v e t o u s e \ b t o m a t c h w o r d s t h o u g h . Y o u c a n l o o k f o r n o n - w o r d c h a r a c t e r s s u r r o u n d e d b y w o r d c h a r a c t e r s . T h e s e s t r i n g s m a t c h t h e p a t t e r n / \ b ' \ b / .
"don't" # the ' char is surrounded by "n" and "t"
"qep'a'" # the ' char is surrounded by "p" and "a"
T h e s e s t r i n g s d o n o t m a t c h / \ b ' \ b / .
"foo'" # there is no word char after non-word '
Y o u c a n a l s o u s e t h e c o m p l e m e n t o f \ b , \ B , t o s p e c i f y t h a t t h e r e s h o u l d n o t b e a w o r d b o u n d a r y .
I n t h e p a t t e r n / \ B a m \ B / , t h e r e m u s t b e a w o r d c h a r a c t e r b e f o r e t h e " a " a n d a f t e r t h e " m " . T h e s e p a t t e r n s m a t c h / \ B a m \ B / :
"llama" # "am" surrounded by word chars
"Samuel" # same
T h e s e s t r i n g s d o n o t m a t c h / \ B a m \ B /
"Sam" # no word boundary before "a", but one after "m"
"I am Sam" # "am" surrounded by non-word chars
# W h y d o e s u s i n g $ & , $ ` , o r $ ' s l o w m y p r o g r a m d o w n ?
( c o n t r i b u t e d b y A n n o S i e g e l )
O n c e P e r l s e e s t h a t y o u n e e d o n e o f t h e s e v a r i a b l e s a n y w h e r e i n t h e p r o g r a m , i t p r o v i d e s t h e m o n e a c h a n d e v e r y p a t t e r n m a t c h . T h a t m e a n s t h a t o n e v e r y p a t t e r n m a t c h t h e e n t i r e s t r i n g w i l l b e c o p i e d , p a r t o f i t t o $ ` , p a r t t o $ & , a n d p a r t t o $ ' . T h u s t h e p e n a l t y i s m o s t s e v e r e w i t h l o n g s t r i n g s a n d p a t t e r n s t h a t m a t c h o f t e n . A v o i d $ & , $ ' , a n d $ ` i f y o u c a n , b u t i f y o u c a n ' t , o n c e y o u ' v e u s e d t h e m a t a l l , u s e t h e m a t w i l l b e c a u s e y o u ' v e a l r e a d y p a i d t h e p r i c e . R e m e m b e r t h a t s o m e a l g o r i t h m s r e a l l y a p p r e c i a t e t h e m . A s o f t h e 5 . 0 0 5 r e l e a s e , t h e $ & v a r i a b l e i s n o l o n g e r " e x p e n s i v e " t h e w a y t h e o t h e r t w o a r e .
S i n c e P e r l 5 . 6 . 1 t h e s p e c i a l v a r i a b l e s @ - a n d @ + c a n f u n c t i o n a l l y r e p l a c e $ ` , $ & a n d $ ' . T h e s e a r r a y s c o n t a i n p o i n t e r s t o t h e b e g i n n i n g a n d e n d o f e a c h m a t c h ( s e e p e r l v a r f o r t h e f u l l s t o r y ) , s o t h e y g i v e y o u e s s e n t i a l l y t h e s a m e i n f o r m a t i o n , b u t w i t h o u t t h e r i s k o f e x c e s s i v e s t r i n g c o p y i n g .
P e r l 5 . 1 0 a d d e d t h r e e s p e c i a l s , $ { ^ M A T C H }
, $ { ^ P R E M A T C H }
, a n d $ { ^
P O S T M A T C H }
t o d o t h e s a m e j o b b u t w i t h o u t t h e g l o b a l p e r f o r m a n c e p e n a l t y . P e r l 5 . 1 0 o n l y s e t s t h e s e v a r i a b l e s i f y o u c o m p i l e o r e x e c u t e t h e r e g u l a r e x p r e s s i o n w i t h t h e / p
m o d i f i e r .
# W h a t g o o d i s \ G
i n a r e g u l a r e x p r e s s i o n ?
Y o u u s e t h e \ G
a n c h o r t o s t a r t t h e n e x t m a t c h o n t h e s a m e s t r i n g w h e r e t h e l a s t m a t c h l e f t o f f . T h e r e g u l a r e x p r e s s i o n e n g i n e c a n n o t s k i p o v e r a n y c h a r a c t e r s t o f i n d t h e n e x t m a t c h w i t h t h i s a n c h o r , s o \ G
i s s i m i l a r t o t h e b e g i n n i n g o f s t r i n g a n c h o r , ^
. T h e \ G
a n c h o r i s t y p i c a l l y u s e d w i t h t h e g
f l a g . I t u s e s t h e v a l u e o f p o s ( )
a s t h e p o s i t i o n t o s t a r t t h e n e x t m a t c h . A s t h e m a t c h o p e r a t o r m a k e s s u c c e s s i v e m a t c h e s , i t u p d a t e s p o s ( )
w i t h t h e p o s i t i o n o f t h e n e x t c h a r a c t e r p a s t t h e l a s t m a t c h ( o r t h e f i r s t c h a r a c t e r o f t h e n e x t m a t c h , d e p e n d i n g o n h o w y o u l i k e t o l o o k a t i t ) . E a c h s t r i n g h a s i t s o w n p o s ( )
v a l u e .
S u p p o s e y o u w a n t t o m a t c h a l l o f c o n s e c u t i v e p a i r s o f d i g i t s i n a s t r i n g l i k e " 1 1 2 2 a 4 4 " a n d s t o p m a t c h i n g w h e n y o u e n c o u n t e r n o n - d i g i t s . Y o u w a n t t o m a t c h 11
a n d 22
b u t t h e l e t t e r < a > s h o w s u p b e t w e e n 22
a n d 44
a n d y o u w a n t t o s t o p a t a
. S i m p l y m a t c h i n g p a i r s o f d i g i t s s k i p s o v e r t h e a
a n d s t i l l m a t c h e s 44
.
$_ = "1122a44";
my @pairs = m/(\d\d)/g; # qw( 11 22 44 )
I f y o u u s e t h e \ G
a n c h o r , y o u f o r c e t h e m a t c h a f t e r 22
t o s t a r t w i t h t h e a
. T h e r e g u l a r e x p r e s s i o n c a n n o t m a t c h t h e r e s i n c e i t d o e s n o t f i n d a d i g i t , s o t h e n e x t m a t c h f a i l s a n d t h e m a t c h o p e r a t o r r e t u r n s t h e p a i r s i t a l r e a d y f o u n d .
$_ = "1122a44";
my @pairs = m/\G(\d\d)/g; # qw( 11 22 )
Y o u c a n a l s o u s e t h e \ G
a n c h o r i n s c a l a r c o n t e x t . Y o u s t i l l n e e d t h e g
f l a g .
$_ = "1122a44";
while( m/\G(\d\d)/g ) {
print "Found $1\n";
}
A f t e r t h e m a t c h f a i l s a t t h e l e t t e r a
, p e r l r e s e t s p o s ( )
a n d t h e n e x t m a t c h o n t h e s a m e s t r i n g s t a r t s a t t h e b e g i n n i n g .
$_ = "1122a44";
while( m/\G(\d\d)/g ) {
print "Found $1\n";
}
print "Found $1 after while" if m/(\d\d)/g; # finds "11"
Y o u c a n d i s a b l e p o s ( )
r e s e t s o n f a i l w i t h t h e c
f l a g , d o c u m e n t e d i n p e r l o p a n d p e r l r e r e f . S u b s e q u e n t m a t c h e s s t a r t w h e r e t h e l a s t s u c c e s s f u l m a t c h e n d e d ( t h e v a l u e o f p o s ( )
) e v e n i f a m a t c h o n t h e s a m e s t r i n g h a s f a i l e d i n t h e m e a n t i m e . I n t h i s c a s e , t h e m a t c h a f t e r t h e w h i l e ( )
l o o p s t a r t s a t t h e a
( w h e r e t h e l a s t m a t c h s t o p p e d ) , a n d s i n c e i t d o e s n o t u s e a n y a n c h o r i t c a n s k i p o v e r t h e a
t o f i n d 44
.
$_ = "1122a44";
while( m/\G(\d\d)/gc ) {
print "Found $1\n";
}
print "Found $1 after while" if m/(\d\d)/g; # finds "44"
T y p i c a l l y y o u u s e t h e \ G
a n c h o r w i t h t h e c
f l a g w h e n y o u w a n t t o t r y a d i f f e r e n t m a t c h i f o n e f a i l s , s u c h a s i n a t o k e n i z e r . J e f f r e y F r i e d l o f f e r s t h i s e x a m p l e w h i c h w o r k s i n 5 . 0 0 4 o r l a t e r .
while (<>) {
chomp;
PARSER: {
m/ \G( \d+\b )/gcx && do { print "number: $1\n"; redo; };
m/ \G( \w+ )/gcx && do { print "word: $1\n"; redo; };
m/ \G( \s+ )/gcx && do { print "space: $1\n"; redo; };
m/ \G( [^\w\d]+ )/gcx && do { print "other: $1\n"; redo; };
}
}
F o r e a c h l i n e , t h e P A R S E R
l o o p f i r s t t r i e s t o m a t c h a s e r i e s o f d i g i t s f o l l o w e d b y a w o r d b o u n d a r y . T h i s m a t c h h a s t o s t a r t a t t h e p l a c e t h e l a s t m a t c h l e f t o f f ( o r t h e b e g i n n i n g o f t h e s t r i n g o n t h e f i r s t m a t c h ) . S i n c e m / \
G ( \ d + \ b ) / g c x
u s e s t h e c
f l a g , i f t h e s t r i n g d o e s n o t m a t c h t h a t r e g u l a r e x p r e s s i o n , p e r l d o e s n o t r e s e t p o s ( ) a n d t h e n e x t m a t c h s t a r t s a t t h e s a m e p o s i t i o n t o t r y a d i f f e r e n t p a t t e r n .
# A r e P e r l r e g e x e s D F A s o r N F A s ? A r e t h e y P O S I X c o m p l i a n t ?
W h i l e i t ' s t r u e t h a t P e r l ' s r e g u l a r e x p r e s s i o n s r e s e m b l e t h e D F A s ( d e t e r m i n i s t i c f i n i t e a u t o m a t a ) o f t h e e g r e p ( 1 ) p r o g r a m , t h e y a r e i n f a c t i m p l e m e n t e d a s N F A s ( n o n - d e t e r m i n i s t i c f i n i t e a u t o m a t a ) t o a l l o w b a c k t r a c k i n g a n d b a c k r e f e r e n c i n g . A n d t h e y a r e n ' t P O S I X - s t y l e e i t h e r , b e c a u s e t h o s e g u a r a n t e e w o r s t - c a s e b e h a v i o r f o r a l l c a s e s . ( I t s e e m s t h a t s o m e p e o p l e p r e f e r g u a r a n t e e s o f c o n s i s t e n c y , e v e n w h e n w h a t ' s g u a r a n t e e d i s s l o w n e s s . ) S e e t h e b o o k " M a s t e r i n g R e g u l a r E x p r e s s i o n s " ( f r o m O ' R e i l l y ) b y J e f f r e y F r i e d l f o r a l l t h e d e t a i l s y o u c o u l d e v e r h o p e t o k n o w o n t h e s e m a t t e r s ( a f u l l c i t a t i o n a p p e a r s i n p e r l f a q 2 ) .
# W h a t ' s w r o n g w i t h u s i n g g r e p i n a v o i d c o n t e x t ?
T h e p r o b l e m i s t h a t g r e p b u i l d s a r e t u r n l i s t , r e g a r d l e s s o f t h e c o n t e x t . T h i s m e a n s y o u ' r e m a k i n g P e r l g o t o t h e t r o u b l e o f b u i l d i n g a l i s t t h a t y o u t h e n j u s t t h r o w a w a y . I f t h e l i s t i s l a r g e , y o u w a s t e b o t h t i m e a n d s p a c e . I f y o u r i n t e n t i s t o i t e r a t e o v e r t h e l i s t , t h e n u s e a f o r l o o p f o r t h i s p u r p o s e .
I n p e r l s o l d e r t h a n 5 . 8 . 1 , m a p s u f f e r s f r o m t h i s p r o b l e m a s w e l l . B u t s i n c e 5 . 8 . 1 , t h i s h a s b e e n f i x e d , a n d m a p i s c o n t e x t a w a r e - i n v o i d c o n t e x t , n o l i s t s a r e c o n s t r u c t e d .
# H o w c a n I m a t c h s t r i n g s w i t h m u l t i b y t e c h a r a c t e r s ?
S t a r t i n g f r o m P e r l 5 . 6 P e r l h a s h a d s o m e l e v e l o f m u l t i b y t e c h a r a c t e r s u p p o r t . P e r l 5 . 8 o r l a t e r i s r e c o m m e n d e d . S u p p o r t e d m u l t i b y t e c h a r a c t e r r e p e r t o i r e s i n c l u d e U n i c o d e , a n d l e g a c y e n c o d i n g s t h r o u g h t h e E n c o d e m o d u l e . S e e p e r l u n i i n t r o , p e r l u n i c o d e , a n d E n c o d e .
I f y o u a r e s t u c k w i t h o l d e r P e r l s , y o u c a n d o U n i c o d e w i t h t h e U n i c o d e : : S t r i n g m o d u l e , a n d c h a r a c t e r c o n v e r s i o n s u s i n g t h e U n i c o d e : : M a p 8 a n d U n i c o d e : : M a p m o d u l e s . I f y o u a r e u s i n g J a p a n e s e e n c o d i n g s , y o u m i g h t t r y u s i n g t h e j p e r l 5 . 0 0 5 _ 0 3 .
F i n a l l y , t h e f o l l o w i n g s e t o f a p p r o a c h e s w a s o f f e r e d b y J e f f r e y F r i e d l , w h o s e a r t i c l e i n i s s u e # 5 o f T h e P e r l J o u r n a l t a l k s a b o u t t h i s v e r y m a t t e r .
L e t ' s s u p p o s e y o u h a v e s o m e w e i r d M a r t i a n e n c o d i n g w h e r e p a i r s o f A S C I I u p p e r c a s e l e t t e r s e n c o d e s i n g l e M a r t i a n l e t t e r s ( i . e . t h e t w o b y t e s " C V " m a k e a s i n g l e M a r t i a n l e t t e r , a s d o t h e t w o b y t e s " S G " , " V S " , " X X " , e t c . ) . O t h e r b y t e s r e p r e s e n t s i n g l e c h a r a c t e r s , j u s t l i k e A S C I I .
S o , t h e s t r i n g o f M a r t i a n " I a m C V S G X X ! " u s e s 1 2 b y t e s t o e n c o d e t h e n i n e c h a r a c t e r s ' I ' , ' ' , ' a ' , ' m ' , ' ' , ' C V ' , ' S G ' , ' X X ' , ' ! ' .
N o w , s a y y o u w a n t t o s e a r c h f o r t h e s i n g l e c h a r a c t e r / G X /
. P e r l d o e s n ' t k n o w a b o u t M a r t i a n , s o i t ' l l f i n d t h e t w o b y t e s " G X " i n t h e " I a m C V S G X X ! " s t r i n g , e v e n t h o u g h t h a t c h a r a c t e r i s n ' t t h e r e : i t j u s t l o o k s l i k e i t i s b e c a u s e " S G " i s n e x t t o " X X " , b u t t h e r e ' s n o r e a l " G X " . T h i s i s a b i g p r o b l e m .
H e r e a r e a f e w w a y s , a l l p a i n f u l , t o d e a l w i t h i t :
# Make sure adjacent "martian" bytes are no longer adjacent.
$martian =~ s/([A-Z][A-Z])/ $1 /g;
print "found GX!\n" if $martian =~ /GX/;
O r l i k e t h i s :
my @chars = $martian =~ m/([A-Z][A-Z]|[^A-Z])/g;
# above is conceptually similar to: my @chars = $text =~ m/(.)/g;
#
foreach my $char (@chars) {
print "found GX!\n", last if $char eq 'GX';
}
O r l i k e t h i s :
while ($martian =~ m/\G([A-Z][A-Z]|.)/gs) { # \G probably unneeded
if ($1 eq 'GX') {
print "found GX!\n";
last;
}
}
H e r e ' s a n o t h e r , s l i g h t l y l e s s p a i n f u l , w a y t o d o i t f r o m B e n j a m i n G o l d b e r g , w h o u s e s a z e r o - w i d t h n e g a t i v e l o o k - b e h i n d a s s e r t i o n .
print "found GX!\n" if $martian =~ m/
(?<![A-Z])
(?:[A-Z][A-Z])*?
GX
/x;
T h i s s u c c e e d s i f t h e " m a r t i a n " c h a r a c t e r G X i s i n t h e s t r i n g , a n d f a i l s o t h e r w i s e . I f y o u d o n ' t l i k e u s i n g ( ? < ! ) , a z e r o - w i d t h n e g a t i v e l o o k - b e h i n d a s s e r t i o n , y o u c a n r e p l a c e ( ? < ! [ A - Z ] ) w i t h ( ? : ^ | [ ^ A - Z ] ) .
I t d o e s h a v e t h e d r a w b a c k o f p u t t i n g t h e w r o n g t h i n g i n $ - [ 0 ] a n d $ + [ 0 ] , b u t t h i s u s u a l l y c a n b e w o r k e d a r o u n d .
# H o w d o I m a t c h a r e g u l a r e x p r e s s i o n t h a t ' s i n a v a r i a b l e ?
( c o n t r i b u t e d b y b r i a n d f o y )
W e d o n ' t h a v e t o h a r d - c o d e p a t t e r n s i n t o t h e m a t c h o p e r a t o r ( o r a n y t h i n g e l s e t h a t w o r k s w i t h r e g u l a r e x p r e s s i o n s ) . W e c a n p u t t h e p a t t e r n i n a v a r i a b l e f o r l a t e r u s e .
T h e m a t c h o p e r a t o r i s a d o u b l e q u o t e c o n t e x t , s o y o u c a n i n t e r p o l a t e y o u r v a r i a b l e j u s t l i k e a d o u b l e q u o t e d s t r i n g . I n t h i s c a s e , y o u r e a d t h e r e g u l a r e x p r e s s i o n a s u s e r i n p u t a n d s t o r e i t i n $ r e g e x
. O n c e y o u h a v e t h e p a t t e r n i n $ r e g e x
, y o u u s e t h a t v a r i a b l e i n t h e m a t c h o p e r a t o r .
chomp( my $regex = <STDIN> );
if( $string =~ m/$regex/ ) { ... }
A n y r e g u l a r e x p r e s s i o n s p e c i a l c h a r a c t e r s i n $ r e g e x
a r e s t i l l s p e c i a l , a n d t h e p a t t e r n s t i l l h a s t o b e v a l i d o r P e r l w i l l c o m p l a i n . F o r i n s t a n c e , i n t h i s p a t t e r n t h e r e i s a n u n p a i r e d p a r e n t h e s i s .
my $regex = "Unmatched ( paren";
"Two parens to bind them all" =~ m/$regex/;
W h e n P e r l c o m p i l e s t h e r e g u l a r e x p r e s s i o n , i t t r e a t s t h e p a r e n t h e s i s a s t h e s t a r t o f a m e m o r y m a t c h . W h e n i t d o e s n ' t f i n d t h e c l o s i n g p a r e n t h e s i s , i t c o m p l a i n s :
Unmatched ( in regex; marked by <-- HERE in m/Unmatched ( <-- HERE paren/ at script line 3.
Y o u c a n g e t a r o u n d t h i s i n s e v e r a l w a y s d e p e n d i n g o n o u r s i t u a t i o n . F i r s t , i f y o u d o n ' t w a n t a n y o f t h e c h a r a c t e r s i n t h e s t r i n g t o b e s p e c i a l , y o u c a n e s c a p e t h e m w i t h q u o t e m e t a
b e f o r e y o u u s e t h e s t r i n g .
chomp( my $regex = <STDIN> );
$regex = quotemeta( $regex );
if( $string =~ m/$regex/ ) { ... }
Y o u c a n a l s o d o t h i s d i r e c t l y i n t h e m a t c h o p e r a t o r u s i n g t h e \ Q
a n d \ E
s e q u e n c e s . T h e \ Q
t e l l s P e r l w h e r e t o s t a r t e s c a p i n g s p e c i a l c h a r a c t e r s , a n d t h e \ E
t e l l s i t w h e r e t o s t o p ( s e e p e r l o p f o r m o r e d e t a i l s ) .
chomp( my $regex = <STDIN> );
if( $string =~ m/\Q$regex\E/ ) { ... }
A l t e r n a t e l y , y o u c a n u s e q r / /
, t h e r e g u l a r e x p r e s s i o n q u o t e o p e r a t o r ( s e e p e r l o p f o r m o r e d e t a i l s ) . I t q u o t e s a n d p e r h a p s c o m p i l e s t h e p a t t e r n , a n d y o u c a n a p p l y r e g u l a r e x p r e s s i o n f l a g s t o t h e p a t t e r n .
chomp( my $input = <STDIN> );
my $regex = qr/$input/is;
$string =~ m/$regex/ # same as m/$input/is;
Y o u m i g h t a l s o w a n t t o t r a p a n y e r r o r s b y w r a p p i n g a n e v a l
b l o c k a r o u n d t h e w h o l e t h i n g .
chomp( my $input = <STDIN> );
eval {
if( $string =~ m/\Q$input\E/ ) { ... }
};
warn $@ if $@;
O r . . .
my $regex = eval { qr/$input/is };
if( defined $regex ) {
$string =~ m/$regex/;
}
else {
warn $@;
}
# A U T H O R A N D C O P Y R I G H T
C o p y r i g h t ( c ) 1 9 9 7 - 2 0 1 0 T o m C h r i s t i a n s e n , N a t h a n T o r k i n g t o n , a n d o t h e r a u t h o r s a s n o t e d . A l l r i g h t s r e s e r v e d .
T h i s d o c u m e n t a t i o n i s f r e e ; y o u c a n r e d i s t r i b u t e i t a n d / o r m o d i f y i t u n d e r t h e s a m e t e r m s a s P e r l i t s e l f .
I r r e s p e c t i v e o f i t s d i s t r i b u t i o n , a l l c o d e e x a m p l e s i n t h i s f i l e a r e h e r e b y p l a c e d i n t o t h e p u b l i c d o m a i n . Y o u a r e p e r m i t t e d a n d e n c o u r a g e d t o u s e t h i s c o d e i n y o u r o w n p r o g r a m s f o r f u n o r f o r p r o f i t a s y o u s e e f i t . A s i m p l e c o m m e n t i n t h e c o d e g i v i n g c r e d i t w o u l d b e c o u r t e o u s b u t i s n o t r e q u i r e d .
P e r l d o c B r o w s e r i s m a i n t a i n e d b y D a n B o o k ( D B O O K ) . P l e a s e c o n t a c t h i m v i a t h e G i t H u b i s s u e t r a c k e r or e m a i l r e g a r d i n g a n y i s s u e s w i t h t h e s i t e i t s e l f , s e a r c h , o r r e n d e r i n g o f d o c u m e n t a t i o n .
T h e P e r l d o c u m e n t a t i o n i s m a i n t a i n e d b y t h e P e r l 5 P o r t e r s i n t h e d e v e l o p m e n t o f P e r l . P l e a s e c o n t a c t t h e m v i a t h e P e r l i s s u e t r a c k e r , t h e m a i l i n g l i s t , o r I R C t o r e p o r t a n y i s s u e s w i t h t h e c o n t e n t s o r f o r m a t o f t h e d o c u m e n t a t i o n .