Regular Expressions and Matching (Modern Perl 2011-2012)

文章推薦指數: 80 %
投票人數:10人

Perl's text processing power comes from its use of regular expressions. A regular expression (regex or regexp) is a pattern which describes characteristics ... ModernPerl:2011-2012edition TableofContents Index ModernPerlBooks Contents Preface ThePerlPhilosophy PerlandItsCommunity ThePerlLanguage Operators Functions →RegularExpressions&Matching← Objects StyleandEfficacy ManagingRealPrograms PerlBeyondSyntax WhattoAvoid What'sMissing TableofContents Index Thisbookisfree! VisitModernPerltodownloadyourowncopyofthisbook.Youcanalsobuyaprintedcopy! ModernPerlatPowell'sModernPerlatB&NModernPerlatAmazon ©2010-2012chromatic PublishedbyOnyxNeon RegularExpressionsandMatching Perl'stextprocessingpowercomesfromitsuseofregularexpressions.Aregularexpression(regexorregexp)isapatternwhichdescribescharacteristicsofapieceoftext.Aregularexpressionengineinterpretspatternsandappliesthemtomatchormodifypiecesoftext. Perl'scoreregexdocumentationincludesatutorial(perldocperlretut),areferenceguide(perldocperlreref),andfulldocumentation(perldocperlre).JeffreyFriedl'sbookMasteringRegularExpressionsexplainsthetheoryandthemechanicsofhowregularexpressionswork.Whilemasteringregularexpressionsisadauntingpursuit,alittleknowledgewillgiveyougreatpower. Literals Regexescanbeassimpleassubstringpatterns: my$name='Chatfield'; say'Foundahat!'if$name=~/hat/; Thematchoperator(m//,abbreviated//)identifiesaregularexpression—inthisexample,hat.Thispatternisnotaword.Insteaditmeans"thehcharacter,followedbytheacharacter,followedbythetcharacter."Eachcharacterinthepatternisanindivisibleelement,oratom.Itmatchesoritdoesn't. Theregexbindingoperator(=~)isaninfixoperator(Fixity)whichappliestheregexofitssecondoperandtoastringprovidedbyitsfirstoperand.Whenevaluatedinscalarcontext,amatchevaluatestoatruevalueifitsucceeds.Thenegatedformofthebindingoperator(!~)evaluatestoatruevalueunlessthematchsucceeds. Rememberindex! Theindexbuiltincanalsosearchforaliteralsubstringwithinastring.Usingaregexengineforthatislikeflyingyourautonomouscombathelicoptertothecornerstoretobuycheese—butPerlallowsyoutodecidewhatyoufindmostmaintainable. Thesubstitutionoperator,s///,isinonesenseacircumfixoperator(Fixity)withtwooperands.Itsfirstoperandisaregularexpressiontomatchwhenusedwiththeregexbindingoperator.Thesecondoperandisasubstringusedtoreplacethematchedportionofthefirstoperandusedwiththeregexbindingoperator.Forexample,tocurepeskysummerallergies: my$status='Ifeelill.'; $status=~s/ill/well/; say$status; Theqr//OperatorandRegexCombinations Theqr//operatorcreatesfirst-classregexes.Interpolatethemintothematchoperatortousethem: my$hat=qr/hat/; say'Foundahat!'if$name=~/$hat/; ...orcombinemultipleregexobjectsintocomplexpatterns: my$hat=qr/hat/; my$field=qr/field/; say'Foundahatinafield!' if$name=~/$hat$field/; like($name,qr/$hat$field/, 'Foundahatinafield!'); Likeis,withMorelike Test::More'slikefunctionteststhatthefirstargumentmatchestheregexprovidedasthesecondargument. Quantifiers Regularexpressionsgetmorepowerfulthroughtheuseofregexquantifiers,whichallowyoutospecifyhowoftenaregexcomponentmayappearinamatchingstring.Thesimplestquantifieristhezerooronequantifier,or?: my$cat_or_ct=qr/ca?t/; like('cat',$cat_or_ct,"'cat'matches/ca?t/"); like('ct',$cat_or_ct,"'ct'matches/ca?t/"); Anyatominaregularexpressionfollowedbythe?charactermeans"matchzerooroneofthisatom."Thisregularexpressionmatchesifzerooroneacharactersimmediatelyfollowaccharacterandimmediatelyprecedeatcharacter,eithertheliteralsubstringcatorct. Theoneormorequantifier,or+,matchesonlyifthereisatleastoneofthequantifiedatom: my$some_a=qr/ca+t/; like('cat',$some_a,"'cat'matches/ca+t/"); like('caat',$some_a,"'caat'matches/"); like('caaat',$some_a,"'caaat'matches"); like('caaaat',$some_a,"'caaaat'matches"); unlike('ct',$some_a,"'ct'doesnotmatch"); Thereisnotheoreticallimittothemaximumnumberofquantifiedatomswhichcanmatch. Thezeroormorequantifier,*,matcheszeroormoreinstancesofthequantifiedatom: my$any_a=qr/ca*t/; like('cat',$any_a,"'cat'matches/ca*t/"); like('caat',$any_a,"'caat'matches"); like('caaat',$any_a,"'caaat'matches"); like('caaaat',$any_a,"'caaaat'matches"); like('ct',$any_a,"'ct'matches"); Assillyasthisseems,itallowsyoutospecifyoptionalcomponentsofaregex.Useitsparingly,though:it'sabluntandexpensivetool.Mostregularexpressionsbenefitfromusingthe?and+quantifiersfarmorethan*.Precisionofintentoftenimprovesclarity. Numericquantifiersexpressspecificnumbersoftimesanatommaymatch.{n}meansthatamatchmustoccurexactlyntimes. #equivalenttoqr/cat/; my$only_one_a=qr/ca{1}t/; like('cat',$only_one_a,"'cat'matches/ca{1}t/"); {n,}matchesanatomatleastntimes: #equivalenttoqr/ca+t/; my$some_a=qr/ca{1,}t/; like('cat',$some_a,"'cat'matches/ca{1,}t/"); like('caat',$some_a,"'caat'matches"); like('caaat',$some_a,"'caaat'matches"); like('caaaat',$some_a,"'caaaat'matches"); {n,m}meansthatamatchmustoccuratleastntimesandcannotoccurmorethanmtimes: my$few_a=qr/ca{1,3}t/; like('cat',$few_a,"'cat'matches/ca{1,3}t/"); like('caat',$few_a,"'caat'matches"); like('caaat',$few_a,"'caaat'matches"); unlike('caaaat',$few_a,"'caaaat'doesn'tmatch"); Youmayexpressthesymbolicquantifiersintermsofthenumericquantifiers,butmostprogramsusetheformerfarmoreoftenthanthelatter. Greediness The+and*quantifiersaregreedy,astheytrytomatchasmuchoftheinputstringaspossible.Thisisparticularlypernicious.Consideranaïveuseofthe"zeroormorenon-newlinecharacters"patternof.*: #apoorregex my$hot_meal=qr/hot.*meal/; say'Foundahotmeal!' if'Ihaveahotmeal'=~$hot_meal; say'Foundahotmeal!' if'one-shot,piecemealwork!'=~$hot_meal; Greedyquantifiersstartbymatchingeverythingatfirst,andbackoffacharacteratatimeonlywhenit'sobviousthatthematchwillnotsucceed. The?quantifiermodifierturnsagreedy-quantifierparsimonious: my$minimal_greedy=qr/hot.*?meal/; Whengivenanon-greedyquantifier,theregularexpressionenginewillprefertheshortestpossiblepotentialmatchandwillincreasethenumberofcharactersidentifiedbythe.*?tokencombinationonlyifthecurrentnumberfailstomatch.Because*matcheszeroormoretimes,theminimalpotentialmatchforthistokencombinationiszerocharacters: say'Foundahotmeal' if'ilikeahotmeal'=~/$minimal_greedy/; Use+?tomatchoneormoreitemsnon-greedily: my$minimal_greedy_plus=qr/hot.+?meal/; unlike('ilikeahotmeal',$minimal_greedy_plus); like('ilikeahotmeal',$minimal_greedy_plus); The?quantifiermodifieralsoappliestothe?(zerooronematches)quantifieraswellastherangequantifiers.Ineverycase,itcausestheregextomatchaslittleoftheinputaspossible. Thegreedypatterns.+and.*aretemptingbutdangerous.AcruciverbalistAcrosswordpuzzleafficionado.whoneedstofillinfourboxesof7Down("Richsoil")willfindtoomanyinvalidcandidateswiththepattern: my$seven_down=qr/l$letters_only*m/; She'llhavetodiscardAlabama,Belgium,andBethlehemlongbeforetheprogramsuggestsloam.Notonlyarethosewordstoolong,butthematchesstartinthemiddleofthewords.Aworkingunderstandingofgreedinesshelps,butthereisnosubstituteforthecopioustestingwithreal,workingdata. RegexAnchors Regexanchorsforcetheregexenginetostartorendamatchatanabsoluteposition.Thestartofstringanchor(\A)dictatesthatanymatchmuststartatthebeginningofthestring: #alsomatches"lammed","lawmaker",and"layman" my$seven_down=qr/\Al${letters_only}{2}m/; Theendoflinestringanchor(\Z)requiresthatamatchendattheendofalinewithinthestring. #alsomatches"loom",butanobviousimprovement my$seven_down=qr/\Al${letters_only}{2}m\Z/; Thewordboundaryanchor(\b)matchesonlyattheboundarybetweenawordcharacter(\w)andanon-wordcharacter(\W).UseananchoredregextofindloamwhileprohibitingBelgium: my$seven_down=qr/\bl${letters_only}{2}m\b/; Metacharacters Perlinterpretsseveralcharactersinregularexpressionsasmetacharacters,charactersrepresentsomethingotherthantheirliteralinterpretation.Metacharactersgiveregexwielderspowerfarbeyondmeresubstringmatches.Theregexenginetreatsallmetacharactersasatoms. The.metacharactermeans"matchanycharacterexceptanewline".Rememberthatcaveat;manynovicesforgetit.Asimpleregexsearch—ignoringtheobviousimprovementofusinganchors—for7Downmightbe/l..m/.Ofcourse,there'salwaysmorethanonewaytogettherightanswer: formy$word(@words) { nextunlesslength($word)==4; nextunless$word=~/l..m/; say"Possibility:$word"; } Ifthepotentialmatchesin@wordsaremorethanthesimplestEnglishwords,youwillgetfalsepositives..alsomatchespunctuationcharacters,whitespace,andnumbers.Bespecific!The\wmetacharacterrepresentsallalphanumericcharacters(UnicodeandStrings)andtheunderscore: nextunless$word=~/l\w\wm/; The\dmetacharactermatchesdigits(alsointheUnicodesense): #notarobustphonenumbermatcher nextunless$number=~/\d{3}-\d{3}-\d{4}/; say"Ihaveyournumber:$number"; Usethe\smetacharactertomatchwhitespace,whetheraliteralspace,atabcharacter,acarriagereturn,aform-feed,oranewline: my$two_three_letter_words=qr/\w{3}\s\w{3}/; NegatedMetacharacters Thesemetacharactershavenegatedforms.Use\Wtomatchanycharacterexceptawordcharacter.Use\Dtomatchanon-digitcharacter.Use\Stomatchanythingbutwhitespace.Use\Btomatchanywhereexceptawordboundary. CharacterClasses Whennoneofthosemetacharactersisspecificenough,specifyyourowncharacterclassbyenclosingtheminsquarebrackets: my$ascii_vowels=qr/[aeiou]/; my$maybe_cat=qr/c${ascii_vowels}t/; InterpolationHappens Withoutthosecurlybraces,Perl'sparserwouldinterpretthevariablenameas$ascii_vowelst,whicheithercausesacompile-timeerroraboutanunknownvariableorinterpolatesthecontentsofanexisting$ascii_vowelstintotheregex. Thehyphencharacter(-)allowsyoutospecifyacontiguousrangeofcharactersinaclass,suchasthis$ascii_letters_onlyregex: my$ascii_letters_only=qr/[a-zA-Z]/; Toincludethehyphenasamemberoftheclass,moveittothestartorend: my$interesting_punctuation=qr/[-!?]/; ...orescapeit: my$line_characters=qr/[|=\-_]/; Usethecaret(^)asthefirstelementofthecharacterclasstomean"anythingexceptthesecharacters": my$not_an_ascii_vowel=qr/[^aeiou]/; MetacharactersinCharacterClasses Useacaretanywherebutthefirstpositiontomakeitamemberofthecharacterclass.Toincludeahypheninanegatedcharacterclass,placeitafterthecaretorattheendoftheclass,orescapeit. Capturing Regularexpressionsallowyoutogroupandcaptureportionsofthematchforlateruse.ToextractanAmericantelephonenumberoftheform(202)456-1111fromastring: my$area_code=qr/\(\d{3}\)/; my$local_number=qr/\d{3}-?\d{4}/; my$phone_number=qr/$area_code\s?$local_number/; Noteespeciallytheescapingoftheparentheseswithin$area_code.ParenthesesarespecialinPerl5regularexpressions.Theygroupatomsintolargerunitsandalsocaptureportionsofmatchingstrings.Tomatchliteralparentheses,escapethemwithbackslashesasseenin$area_code. NamedCaptures Perl5.10addednamedcaptures,whichallowyoutocaptureportionsofmatchesfromapplyingaregularexpressionandaccessthemlater,suchasfindingaphonenumberinastringofcontactinformation: if($contact_info=~/(?$phone_number)/) { say"Foundanumber$+{phone}"; } Regexestendtolooklikepunctuationsoupuntilyoucangroupvariousportionstogetheraschunks.Namedcapturesyntaxhastheform: (?...) Parenthesesenclosethecapture.The?constructnamesthisparticularcaptureandmustimmediatelyfollowtheleftparenthesis.Theremainderofthecaptureisaregularexpression. Whenamatchagainsttheenclosingpatternsucceeds,Perlstorestheportionofthestringwhichmatchestheenclosedpatterninthemagicvariable%+.Inthishash,thekeyisthenameofthecaptureandthevalueistheappropriateportionofthematchedstring. NumberedCaptures Perlhassupportednumberedcapturesforages: if($contact_info=~/($phone_number)/) { say"Foundanumber$1"; } Thisformofcaptureprovidesnoidentifyingnameanddoesnotstorein%+.Instead,Perlstoresthecapturedsubstringinaseriesofmagicvariables.ThefirstmatchingcapturethatPerlfindsgoesinto$1,thesecondinto$2,andsoon.Capturecountsstartattheopeningparenthesisofthecapture;thusthefirstleftparenthesisbeginsthecaptureinto$1,thesecondinto$2,andsoon. Whilethesyntaxfornamedcapturesislongerthanfornumberedcaptures,itprovidesadditionalclarity.Countingleftparenthesesistediouswork,andcombiningregexeswhicheachcontainnumberedcapturesisfartoodifficult.Namedcapturesimproveregexmaintainability—thoughnamecollisionsarepossible,they'rerelativelyinfrequent.Minimizetheriskbyusingnamedcapturesonlyintop-levelregexes. Inlistcontext,aregexmatchreturnsalistofcapturedsubstrings: if(my($number)=$contact_info=~/($phone_number)/) { say"Foundanumber$number"; } Numberedcapturesarealsousefulinsimplesubstitutions,wherenamedcapturesmaybemoreverbose: my$order='Veganbrownies!'; $order=~s/Vegan(\w+)/Vegetarian$1/; #or $order=~s/Vegan(?\w+)/Vegetarian$+{food}/; GroupingandAlternation Previousexampleshaveallappliedquantifierstosimpleatoms.Youmayapplythemtoanyregexelement: my$pork=qr/pork/; my$beans=qr/beans/; like('porkandbeans',qr/\A$pork?.*?$beans/, 'maybepork,definitelybeans'); Ifyouexpandtheregexmanually,theresultsmaysurpriseyou: my$pork_and_beans=qr/\Apork?.*beans/; like('porkandbeans',qr/$pork_and_beans/, 'maybepork,definitelybeans'); like('porandbeans',qr/$pork_and_beans/, 'wait...nophylloquinonehere!'); Sometimesspecificityhelpspatternaccuracy: my$pork=qr/pork/; my$and=qr/and/; my$beans=qr/beans/; like('porkandbeans',qr/\A$pork?$and?$beans/, 'maybepork,maybeand,definitelybeans'); Someregexesneedtomatcheitheronethingoranother.Thealternationmetacharacter(|)expressesthisintent: my$rice=qr/rice/; my$beans=qr/beans/; like('rice',qr/$rice|$beans/,'Foundrice'); like('beans',qr/$rice|$beans/,'Foundbeans'); Thealternationmetacharacterindicatesthateitherprecedingfragmentmaymatch.Keepinmindthatalternationhasalowerprecedence(Precedence)thanevenatoms: like('rice',qr/rice|beans/,'Foundrice'); like('beans',qr/rice|beans/,'Foundbeans'); unlike('ricb',qr/rice|beans/,'Foundhybrid'); Whileit'seasytointerpretrice|beansasmeaningric,followedbyeithereorb,followedbyeans,alternationsalwaysincludetheentirefragmenttothenearestregexdelimiter,whetherthestartorendofthepattern,anenclosingparenthesis,anotheralternationcharacter,orasquarebracket. Toreduceconfusion,usenamedfragmentsinvariables($rice|$beans)orgroupalternationcandidatesinnon-capturinggroups: my$starches=qr/(?:pasta|potatoes|rice)/; The(?:)sequencegroupsaseriesofatomswithoutmakingacapture. Non-CapturedForYourProtection Astringifiedregularexpressionincludesanenclosingnon-capturinggroup;qr/rice|beans/stringifiesas(?^u:rice|beans). OtherEscapeSequences Tomatchaliteralinstanceofametacharacter,escapeitwithabackslash(\).You'veseenthisbefore,where\(referstoasingleleftparenthesisand\]referstoasinglerightsquarebracket.\.referstoaliteralperiodcharacterinsteadofthe"matchanythingbutanexplicitnewlinecharacter"atom. Youwilllikelyneedtoescapethealternationmetacharacter(|)aswellastheendoflinemetacharacter($)andthequantifiers(+,?,*). Themetacharacterdisablingcharacters(\Qand\E)disablemetacharacterinterpretationwithintheirboundaries.Thisisespeciallyusefulwhentakingmatchtextfromasourceyoudon'tcontrolwhenwritingtheprogram: my($text,$literal_text)=@_; return$text=~/\Q$literal_text\E/; The$literal_textargumentcancontainanything—thestring**ALERT**,forexample.Withinthefragmentboundedby\Qand\E,Perlinterprettheregexas\*\*ALERT\*\*andattempttomatchliteralasteriskcharacters,ratherthangreedyquantifiers. RegexSecurity Becautiouswhenprocessingregularexpressionsfromuntrusteduserinput.Amaliciousregexmastercancraftadenial-of-serviceattackagainstyourprogram. Assertions Regexanchorssuchas\A,\b,\B,and\Zareaformofregexassertion,whichrequiresthatthestringmeetsomecondition.Theseassertionsdonotmatchindividualcharacterswithinthestring.Nomatterwhatthestringcontains,theregexqr/\A/willalwaysmatch.. Zero-widthassertionsmatchapattern.Mostimportantly,theydonotconsumetheportionofthepatternthattheymatch.Forexample,tofindacatonitsown,youmightuseawordboundaryassertion: my$just_a_cat=qr/cat\b/; ...butifyouwanttofindanon-disastrousfeline,youmightuseazero-widthnegativelook-aheadassertion: my$safe_feline=qr/cat(?!astrophe)/; Theconstruct(?!...)matchesthephrasecatonlyifthephraseastrophedoesnotimmediatelyfollow. Thezero-widthpositivelook-aheadassertion: my$disastrous_feline=qr/cat(?=astrophe)/; ...matchesthephrasecatonlyifthephraseastropheimmediatelyfollows.Whileanormalregularexpressioncanaccomplishthesamething,consideraregextofindallnon-catastrophicwordsinthedictionarywhichstartwithcat: my$disastrous_feline=qr/cat(?!astrophe)/; while() { chomp; nextunless/\A(?$disastrous_feline.*)\Z/; say"Foundanon-catastrophe'$+{cat}'"; } Thezero-widthassertionconsumesnoneofthesourcestring,leavingtheanchoredfragment<.>tomatch.Otherwise,thecapturewouldonlycapturethecatportionofthesourcestring. Toassertthatyourfelineneveroccursatthestartofaline,youmightuseazero-widthnegativelook-behindassertion.Theseassertionsmusthavefixedsizes;youmaynotusequantifiers: my$middle_cat=qr/(?(?i)cat)/; The(?i)syntaxenablescase-insensitivematchingonlyforitsenclosinggroup:inthiscase,thenamedcapture.Youmayusemultiplemodifierswiththisform.Disablespecificmodifiersbyprecedingthemwiththeminuscharacter(-): my$find_a_rational=qr/(?(?-i)Rat)/; Themultilineoperator,/m,allowsthe\Aand\Zanchorstomatchatanynewlineembeddedwithinthestring. The/smodifiertreatsthesourcestringasasinglelinesuchthatthe.metacharactermatchesthenewlinecharacter.DamianConwaysuggeststhemnemonicthat/mmodifiesthebehaviorofmultipleregexmetacharacters,while/smodifiesthebehaviorofasingleregexmetacharacter. The/rmodifiercausesasubstitutionoperationtoreturntheresultofthesubstitution,leavingtheoriginalstringas-is.Ifthesubstitutionsucceeds,theresultisamodifiedcopyoftheoriginal.Ifthesubstitutionfails(becausethepatterndoesnotmatch),theresultisanunmodifiedcopyoftheoriginal: my$status='Iamhungryforpie.'; my$newstatus=$status=~s/pie/cake/r; my$statuscopy=$status =~s/liverandonions/bratwurst/r; is($status,'Iamhungryforpie.', 'originalstringshouldbeunmodified'); like($newstatus,qr/cake/,'cakewanted'); unlike($statuscopy,qr/bratwurst/,'wurstnot'); The/xmodifierallowsyoutoembedadditionalwhitespaceandcommentswithinpatterns.Withthismodifierineffect,theregexengineignoreswhitespaceandcomments.Theresultsareoftenmuchmorereadable: my$attr_re=qr{ \A#startofline (?: [;\n\s]*#spacesandsemicolons (?:/\*.*?\*/)?#Ccomments )* ATTR \s+ (U?INTVAL |FLOATVAL |STRING\s+\* ) }x; Thisregexisn'tsimple,butcommentsandwhitespaceimproveitsreadability.Evenifyoucomposeregexestogetherfromcompiledfragments,the/xmodifiercanstillimproveyourcode. The/gmodifiermatchesaregexgloballythroughoutastring.Thismakessensewhenusedwithasubstitution: #appeasetheMitchellestate my$contents=slurp($file); $contents=~s/ScarlettO'Hara/MauveMidway/g; Whenusedwithamatch—notasubstitution—the\Gmetacharacterallowsyoutoprocessastringwithinalooponechunkatatime.\Gmatchesatthepositionwherethemostrecentmatchended.Toprocessapoorly-encodedfilefullofAmericantelephonenumbersinlogicalchunks,youmightwrite: while($contents=~/\G(\w{3})(\w{3})(\w{4})/g) { push@numbers,"($1)$2-$3"; } Beawarethatthe\Ganchorwilltakeupatthelastpointinthestringwherethepreviousiterationofthematchoccurred.Ifthepreviousmatchendedwithagreedymatchsuchas.*,thenextmatchwillhavelessavailablestringtomatch.Lookaheadassertionscanalsohelp. The/emodifierallowsyoutowritearbitraryPerl5codeontherightsideofasubstitutionoperation.Ifthematchsucceeds,theregexenginewillrunthecode,usingitsreturnvalueasthesubstitutionvalue.Theearlierglobalsubstitutionexamplecouldbesimplerwithcodelike: #appeasetheMitchellestate $sequel=~s{Scarlett(O'Hara)?} { 'Mauve'.defined$1 ?'Midway' :'' }ge; Eachadditionaloccurrenceofthe/emodifierwillcauseanotherevaluationoftheresultoftheexpression,thoughonlyPerlgolfersuseanythingbeyond/ee. SmartMatching Thesmartmatchoperator,~~,comparestwooperandsandreturnsatruevalueiftheymatch.Thefuzzinessofthedefinitiondemonstratesthesmartnessoftheoperator:thetypeofcomparisondependsonthetypeofbothoperands.given(Given/When)performsanimplicitsmartmatch. Thesmartmatchoperatorisaninfixoperator: say'Theymatch(somehow)'if$loperand~~$roperand; Thetypeofcomparisongenerallydependsfirstonthetypeoftherightoperandandthenontheleftoperand.Forexample,iftherightoperandisascalarwithanumericcomponent,thecomparisonwillusenumericequality.Iftherightoperandisaregex,thecomparisonwilluseagreporapatternmatch.Iftherightoperandisanarray,thecomparisonwillperformagreporarecursivesmartmatch.Iftherightoperandisahash,thecomparisonwillchecktheexistenceofoneormorekeys.Alargeandintimidatingchartinperldocperlsyngivesfarmoredetailsaboutallthecomparisonssmartmatchcanperform. Aseriousproposalfor5.16suggestssimplifyingsmartmatchsubstantially.Themorecomplexyouroperands,themorelikelyyouaretoreceiveconfusingresults.Avoidcomparingobjectsandsticktosimpleoperationsbetweentwoscalarsoronescalarandoneaggregateforthebestresults. Withthatsaid,smartmatchcanbeuseful: my($x,$y)=(10,20); say'Notequalnumerically'unless$x~~$y; my$z='10littleendians'; say'Equalnumeric-ishally'if$x~~$z; #regularexpressionmatch my$needle=qr/needle/; say'Patternmatch'if'needle'~~$needle; say'Grepthrougharray'if@haystack~~$needle; say'Grepthroughhashkeys'if%hayhash~~$needle; say'Grepthrougharray'if$needle~~@haystack; say'Arrayelementsexistashashkeys' if%hayhash~~@haystack; say'Smartmatchelements'if@straw~~@haystack; say'Grepthroughhashkeys'if$needle~~%hayhash; say'Arrayelementsexistashashkeys' if@haystack~~%hayhash; say'Hashkeysidentical'if%hayhash~~%haymap; Smartmatchworksevenifoneoperandisareferencetothegivendatatype: say'Hashkeysidentical'if%hayhash~~\%hayhash;



請為這篇文章評分?