En guide til Java Regular Expressions API

1. Oversigt

I denne artikel vil vi diskutere Java Regex API, og hvordan regulære udtryk kan bruges i Java-programmeringssprog.

I en verden af ​​regulære udtryk er der mange forskellige varianter at vælge imellem, såsom grep, Perl, Python, PHP, awk og meget mere.

Dette betyder, at et regulært udtryk, der fungerer på et programmeringssprog, muligvis ikke fungerer i et andet. Syntaksen for regulært udtryk i Java ligner mest den, der findes i Perl.

2. Opsætning

For at bruge regulære udtryk i Java behøver vi ingen speciel opsætning. JDK indeholder en speciel pakke java.util.regex helt dedikeret til regex-operationer. Vi behøver kun at importere det til vores kode.

Desuden er java.lang.Streng klasse har også indbygget regex support, som vi ofte bruger i vores kode.

3. Java Regex-pakke

Det java.util.regex pakken består af tre klasser: Mønster, Matcher og MønsterSyntaksUndtagelse:

  • Mønster objekt er en kompileret regex. Det Mønster klasse giver ingen offentlige konstruktører. For at skabe et mønster skal vi først påberåbe sig en af ​​dens offentlige statiske udarbejde metoder, som derefter returnerer a Mønster objekt. Disse metoder accepterer et regulært udtryk som det første argument.
  • Matcher objekt fortolker mønsteret og udfører matchoperationer mod et input Snor. Det definerer også ingen offentlige konstruktører. Vi får en Matcher objekt ved at påberåbe sig matcher metode på en Mønster objekt.
  • MønsterSyntaksundtagelse objekt er en ikke-markeret undtagelse, der angiver en syntaksfejl i et mønster med et regulært udtryk.

Vi vil udforske disse klasser i detaljer; dog skal vi først forstå, hvordan en regex er konstrueret i Java.

Hvis du allerede er bekendt med regex fra et andet miljø, kan du finde visse forskelle, men de er minimale.

4. Enkelt eksempel

Lad os starte med den enkleste brugssag til en regex. Som vi bemærkede tidligere, når en regex anvendes til en streng, kan den matche nul eller flere gange.

Den mest basale form for mønstermatchning understøttet af java.util.regex API er match af en Snor bogstavelig. For eksempel hvis det regulære udtryk er foo og input Snor er foo, vil kampen lykkes, fordi Strenge er identiske:

@Test offentlig ugyldighed givenText_whenSimpleRegexMatches_thenCorrect () {Mønster mønster = Mønster.kompil ("foo"); Matcher matcher = pattern.matcher ("foo"); assertTrue (matcher.find ()); }

Vi opretter først en Mønster objekt ved at kalde dets statiske udarbejde metode og give det et mønster, vi vil bruge.

Så opretter vi en Matcher objekt kalder Mønster objekt matcher metode og videresende den tekst, vi vil kontrollere for matches.

Derefter kalder vi metoden finde i Matcher-objektet.

Det finde metoden fortsætter gennem inputteksten og returnerer sandt for hver kamp, ​​så vi også kan bruge den til at finde matchantal:

@Test offentligt ugyldigt givenText_whenSimpleRegexMatchesTwice_thenCorrect () {Mønster mønster = Mønster.kompil ("foo"); Matcher matcher = pattern.matcher ("foofoo"); int matches = 0; mens (matcher.find ()) {matcher ++; } assertEquals (matches, 2); }

Da vi vil køre flere tests, kan vi abstrakte logikken for at finde antal matches i en metode kaldet runTest:

offentlig statisk int runTest (String regex, String text) {Mønster mønster = Mønster.kompil (regex); Matcher matcher = mønster. Matcher (tekst); int matches = 0; mens (matcher.find ()) {matcher ++; } returnere kampe }

Når vi får 0 kampe, skal testen mislykkes, ellers skal den bestå.

5. Metategn

Metategn påvirker måden, hvorpå et mønster matches, og på en måde tilføjer logik til søgemønsteret. Java API understøtter flere metategn, hvor det mest ligetil er prikken “.” der matcher ethvert tegn:

@Test offentlig ugyldighed givenText_whenMatchesWithDotMetach_thenCorrect () {int matches = runTest (".", "Foo"); assertTrue (matches> 0); }

I betragtning af det foregående eksempel, hvor regex foo matchede teksten foo såvel som foofoo to gange. Hvis vi brugte punktmetacharakteren i regex, ville vi ikke få to matches i det andet tilfælde:

@Test offentlig ugyldighed givenRepeatedText_whenMatchesOnceWithDotMetach_thenCorrect () {int matches = runTest ("foo.", "Foofoo"); assertEquals (matches, 1); }

Bemærk prikken efter foo i regex. Matcheren matcher enhver tekst, der er forud for foo siden den sidste prikdel betyder ethvert tegn efter. Så efter at have fundet den første fooresten ses som enhver karakter. Derfor er der kun en enkelt kamp.

API'en understøtter flere andre metategn som vi vil se nærmere på i denne artikel.

6. Karakterklasser

Gennemse embedsmanden Mønster klassespecifikation, opdager vi resuméer af understøttede regex-konstruktioner. Under karakterklasser har vi omkring 6 konstruktioner.

6.1. ELLER Klasse

Konstrueret som [abc]. Ethvert af elementerne i sættet matches:

@Test offentligt ugyldigt givetORSet_whenMatchesAny_thenCorrect () {int matches = runTest ("[abc]", "b"); assertEquals (matches, 1); }

Hvis de alle vises i teksten, matches de hver for sig uden hensyntagen til rækkefølge:

@Test offentlig ugyldighed givetORSet_whenMatchesAnyAndAll_thenCorrect () {int matches = runTest ("[abc]", "cab"); assertEquals (matches, 3); }

De kan også skiftes som en del af en Snor. I det følgende eksempel, når vi opretter forskellige ord ved at skifte det første bogstav med hvert element i sættet, matches de alle:

@ Test offentligt ugyldigt givetORSet_whenMatchesAllCombinations_thenCorrect () {int matches = runTest ("[bcr] at", "bat cat rat"); assertEquals (matches, 3); }

6.2. HELLER IKKE Klasse

Ovenstående sæt benægtes ved at tilføje et caret som det første element:

@Test offentligt ugyldigt givetNORSet_whenMatchesNon_thenCorrect () {int matches = runTest ("[^ abc]", "g"); assertTrue (matches> 0); }

En anden sag:

@Test offentligt ugyldigt givetNORSet_whenMatchesAllExceptElements_thenCorrect () {int matches = runTest ("[^ bcr] at", "sat mat eat"); assertTrue (matches> 0); }

6.3. Område klasse

Vi kan definere en klasse, der specificerer et område, inden for hvilket den matchede tekst skal falde ved hjælp af en bindestreg (-), ligesom vi også kan negere et interval.

Matchende store bogstaver:

@Test offentlig ugyldighed givenUpperCaseRange_whenMatchesUpperCase_ thenCorrect () {int matches = runTest ("[A-Z]", "To store bogstaver 34 samlet"); assertEquals (matches, 2); }

Matchende små bogstaver:

@Test offentlig ugyldighed givenLowerCaseRange_whenMatchesLowerCase_ thenCorrect () {int matches = runTest ("[a-z]", "To store bogstaver 34 samlet"); assertEquals (matches, 26); }

Matcher både store og små bogstaver:

@Test offentlig ugyldighed givenBothLowerAndUpperCaseRange_ nårMatchesAllLetters_thenCorrect () {int matches = runTest ("[a-zA-Z]", "To store bogstaver 34 samlet"); assertEquals (matches, 28); }

Matcher et givet rækkeområde:

@Test offentlig ugyldighed givenNumberRange_whenMatchesAccurately_ thenCorrect () {int matches = runTest ("[1-5]", "To store bogstaver 34 samlet"); assertEquals (matches, 2); }

Matcher et andet antal numre:

@Test offentlig ugyldighed givenNumberRange_whenMatchesAccurately_ thenCorrect2 () {int matches = runTest ("[30-35]", "To store bogstaver 34 samlet"); assertEquals (matches, 1); }

6.4. Union klasse

En fagforeningskarakterklasse er et resultat af at kombinere to eller flere karakterklasser:

@Test offentlig ugyldighed givenTwoSets_whenMatchesUnion_thenCorrect () {int matches = runTest ("[1-3 [7-9]]", "123456789"); assertEquals (matches, 6); }

Ovenstående test matcher kun 6 ud af de 9 heltal, fordi unionssættet springer 4, 5 og 6 over.

6.5. Kryds klasse

På samme måde som fagklassen er denne klasse resultatet af at vælge fælles elementer mellem to eller flere sæt. For at anvende krydset bruger vi &&:

@Test offentlig ugyldighed givenTwoSets_whenMatchesIntersection_thenCorrect () {int matches = runTest ("[1-6 && [3-9]]", "123456789"); assertEquals (matches, 4); }

Vi får 4 kampe, fordi skæringspunktet mellem de to sæt kun har 4 elementer.

6.6. Subtraktionsklasse

Vi kan bruge subtraktion til at negere en eller flere tegnklasser, for eksempel at matche et sæt ulige decimaltal:

@Test offentlig ugyldighed givenSetWithSubtraction_whenMatchesAccurately_thenCorrect () {int matches = runTest ("[0-9 && [^ 2468]]", "123456789"); assertEquals (matches, 5); }

Kun 1,3,5,7,9 vil blive matchet.

7. Foruddefinerede karakterklasser

Java regex API accepterer også foruddefinerede karakterklasser. Nogle af de ovennævnte karakterklasser kan udtrykkes i kortere form, selvom de gør koden mindre intuitiv. Et specielt aspekt af Java-versionen af ​​denne regex er flugtkarakteren.

Som vi vil se, starter de fleste tegn med en tilbageslag, der har en særlig betydning i Java. For at disse skal udarbejdes af Mønster klasse - det førende tilbageslag skal undslippes, dvs. \ d bliver til \ d.

Matchende cifre svarende til [0-9]:

@Test offentligt ugyldigt givenDigits_whenMatches_thenCorrect () {int matches = runTest ("\ d", "123"); assertEquals (matches, 3); }

Matchende ikke-cifre svarende til [^0-9]:

@Test offentlig ugyldighed givenNonDigits_whenMatches_thenCorrect () {int mathces = runTest ("\ D", "a6c"); assertEquals (matches, 2); }

Matchende hvidt rum:

@Test offentlig ugyldighed givenWhiteSpace_whenMatches_thenCorrect () {int matches = runTest ("\ s", "a c"); assertEquals (matches, 1); }

Matchende ikke-hvidt mellemrum:

@Test offentlig ugyldighed givenNonWhiteSpace_whenMatches_thenCorrect () {int matches = runTest ("\ S", "a c"); assertEquals (matches, 2); }

Matcher et ordkarakter svarende til [a-zA-Z_0-9]:

@Test offentligt ugyldigt givenWordCharacter_whenMatches_thenCorrect () {int matches = runTest ("\ w", "hej!"); assertEquals (matches, 2); }

Matcher et ikke-ord tegn:

@Test offentlig ugyldighed givenNonWordCharacter_whenMatches_thenCorrect () {int matches = runTest ("\ W", "hej!"); assertEquals (matches, 1); }

8. Kvantifikatorer

Java regex API giver os også mulighed for at bruge kvantificeringsmidler. Disse gør det muligt for os yderligere at tilpasse kampens adfærd ved at specificere antallet af hændelser, der skal matches.

For at matche en tekst nul eller en gang bruger vi ? kvantificering:

@Test offentlig ugyldighed givenZeroOrOneQuantifier_whenMatches_thenCorrect () {int matches = runTest ("\ a?", "Hej"); assertEquals (matches, 3); }

Alternativt kan vi bruge afstivningssyntaxen, der også understøttes af Java regex API:

@Test offentlig ugyldighed givenZeroOrOneQuantifier_whenMatches_thenCorrect2 () {int matches = runTest ("\ a {0,1}", "hi"); assertEquals (matches, 3); }

Dette eksempel introducerer begrebet nul-længde matches. Det sker således, at hvis en kvantificerings tærskel for matching er nul, matcher den altid alt i teksten inklusive en tom Snor i slutningen af ​​hvert input. Dette betyder, at selvom input er tomt, returnerer det et match med nul længde.

Dette forklarer, hvorfor vi får 3 matches i ovenstående eksempel på trods af at vi har en String af længde to. Den tredje kamp er tom Snor.

For at matche en tekst nul eller ubegrænsede tider, bruger vi os * kvantificering, den ligner bare?:

@Test offentlig ugyldighed givenZeroOrManyQuantifier_whenMatches_thenCorrect () {int matches = runTest ("\ a *", "hej"); assertEquals (matches, 3); }

Understøttet alternativ:

@Test offentlig ugyldighed givenZeroOrManyQuantifier_whenMatches_thenCorrect2 () {int matches = runTest ("\ a {0,}", "hi"); assertEquals (matches, 3); }

Kvantificeringen med en forskel er +, den har en matchende tærskel på 1. Hvis det kræves Snor forekommer overhovedet ikke, der vil ikke være nogen match, ikke engang en nul-længde Snor:

@Test offentligt ugyldigt givenOneOrManyQuantifier_whenMatches_thenCorrect () {int matches = runTest ("\ a +", "hi"); assertFalse (matches); }

Understøttet alternativ:

@Test offentlig ugyldighed givenOneOrManyQuantifier_whenMatches_thenCorrect2 () {int matches = runTest ("\ a {1,}", "hi"); assertFalse (matches); }

Som det er i Perl og andre sprog, kan afstivningssyntaxen bruges til at matche en given tekst et antal gange:

@Test offentlig ugyldighed givenBraceQuantifier_whenMatches_thenCorrect () {int matches = runTest ("a {3}", "aaaaaa"); assertEquals (matches, 2); }

I ovenstående eksempel får vi to kampe, da en kamp kun finder sted, hvis -en vises tre gange i træk. I den næste test får vi dog ikke et match, da teksten kun vises to gange i træk:

@ Test offentligt ugyldigt givenBraceQuantifier_whenFailsToMatch_thenCorrect () {int matches = runTest ("a {3}", "aa"); assertFalse (matches> 0); }

Når vi bruger et interval i bøjlen, vil matchen være grådig og matche fra den øverste ende af området:

@Test offentlig ugyldighed givenBraceQuantifierWithRange_whenMatches_thenCorrect () {int matches = runTest ("a {2,3}", "aaaa"); assertEquals (matches, 1); }

Vi har specificeret mindst to forekomster, men ikke over tre, så vi får i stedet en enkelt kamp, ​​hvor matcheren ser en enkelt aaa og -en lone a, som ikke kan matches.

API'en giver os dog mulighed for at specificere en doven eller tilbageholdende tilgang, således at matcheren kan starte fra den nedre ende af området, i hvilket tilfælde der matcher to forekomster som aa og aa:

@Test offentlig ugyldighed givenBraceQuantifierWithRange_whenMatchesLazily_thenCorrect () {int matches = runTest ("a {2,3}?", "Aaaa"); assertEquals (matches, 2); }

9. Optagelse af grupper

API'en tillader os også at behandle flere tegn som en enkelt enhed ved at fange grupper.

Det vedhæfter numre til fangegrupperne og tillader referencer tilbage ved hjælp af disse numre.

I dette afsnit vil vi se et par eksempler på, hvordan man bruger optagelsesgrupper i Java regex API.

Lad os bruge en fangstgruppe, der kun matcher, når en inputtekst indeholder to cifre ved siden af ​​hinanden:

@Test offentlig ugyldighed givenCapturingGroup_whenMatches_thenCorrect () {int maches = runTest ("(\ d \ d)", "12"); assertEquals (matches, 1); }

Nummeret knyttet til ovenstående match er 1, ved at bruge en tilbagehenvisning til at fortælle matcheren, at vi vil matche en anden forekomst af den matchede del af teksten. På denne måde i stedet for:

@Test offentlig ugyldighed givenCapturingGroup_whenMatches_thenCorrect2 () {int matches = runTest ("(\ d \ d)", "1212"); assertEquals (matches, 2); }

Hvor der er to separate matches for input, kan vi have en match, men udbrede den samme regex-match for at spænde hele inputets længde ved hjælp af tilbagehenvisning:

@Test offentlig ugyldighed givenCapturingGroup_whenMatchesWithBackReference_ thenCorrect () {int matches = runTest ("(\ d \ d) \ 1", "1212"); assertEquals (matches, 1); }

Hvor vi bliver nødt til at gentage regex uden tilbagehenvisning for at opnå det samme resultat:

@Test offentlig ugyldighed givenCapturingGroup_whenMatches_thenCorrect3 () {int matches = runTest ("(\ d \ d) (\ d \ d)", "1212"); assertEquals (matches, 1); }

Tilsvarende for ethvert andet antal gentagelser, kan referencer tilbage få matcheren til at se input som et enkelt match:

@Test offentlig ugyldighed givenCapturingGroup_whenMatchesWithBackReference_ thenCorrect2 () {int matches = runTest ("(\ d \ d) \ 1 \ 1 \ 1", "12121212"); assertEquals (matches, 1); }

Men hvis du ændrer selv det sidste ciffer, vil matchen mislykkes:

@Test offentlig ugyldighed givenCapturingGroupAndWrongInput_ whenMatchFailsWithBackReference_thenCorrect () {int matches = runTest ("(\ d \ d) \ 1", "1213"); assertFalse (matches> 0); }

Det er vigtigt ikke at glemme flugtets tilbageslag, dette er afgørende i Java-syntaks.

10. Grænsematchere

Java regex API understøtter også grænsetilpasning. Hvis vi er interesserede i, hvor præcist i inputteksten matchet skal forekomme, så er det det, vi leder efter. Med de foregående eksempler var alt, hvad vi plejede, om der blev fundet en kamp eller ej.

For kun at matche, når den krævede regex er sand i begyndelsen af ​​teksten, bruger vi caret ^.

Denne test mislykkes siden teksten hund kan findes i begyndelsen:

@Test offentlig ugyldighed givenText_whenMatchesAtBeginning_thenCorrect () {int matches = runTest ("^ dog", "hunde er venlige"); assertTrue (matches> 0); }

Følgende test mislykkes:

@Test offentlig ugyldighed givenTextAndWrongInput_whenMatchFailsAtBeginning_ thenCorrect () {int matches = runTest ("^ dog", "are hunde er venlige?"); assertFalse (matches> 0); }

For kun at matche, når den krævede regex er sand i slutningen af ​​teksten, bruger vi dollartegnet $. Et match findes i følgende tilfælde:

@Test offentligt ugyldigt givenText_whenMatchesAtEnd_thenCorrect () {int matches = runTest ("dog $", "Mans bedste ven er en hund"); assertTrue (matches> 0); }

Og der findes ikke noget match her:

@Test offentlig ugyldighed givenTextAndWrongInput_whMatchFailsAtEnd_thenCorrect () {int matches = runTest ("dog $", "er en hundes bedste ven?"); assertFalse (matches> 0); }

Hvis vi kun ønsker et match, når den krævede tekst findes ved en ordgrænse, bruger vi \ b regex i begyndelsen og slutningen af ​​regex:

Rummet er en ordgrænse:

@ Test offentligt ugyldigt givenText_whenMatchesAtWordBoundary_thenCorrect () {int matches = runTest ("\ bdog \ b", "a dog is friendly"); assertTrue (matches> 0); }

Den tomme streng i begyndelsen af ​​en linje er også en ordgrænse:

@Test offentligt ugyldigt givenText_whenMatchesAtWordBoundary_thenCorrect2 () {int matches = runTest ("\ bdog \ b", "hund er menneskets bedste ven"); assertTrue (matches> 0); }

Disse tests består, fordi begyndelsen på en Snorsamt mellemrum mellem en tekst og en anden markerer en ordgrænse, men følgende test viser det modsatte:

@ Test offentlig ugyldighed givenWrongText_whenMatchFailsAtWordBoundary_thenCorrect () {int matches = runTest ("\ bdog \ b", "snoop dogg is a rapper"); assertFalse (matches> 0); }

To-ords tegn, der vises i en række, markerer ikke en ordgrænse, men vi kan få det til at passere ved at ændre slutningen af ​​regexen for at lede efter en ikke-ordgrænse:

@ Test offentligt ugyldigt givenText_whenMatchesAtWordAndNonBoundary_thenCorrect () {int matches = runTest ("\ bdog \ B", "snoop dogg is a rapper"); assertTrue (matches> 0); }

11. Mønsterklassemetoder

Tidligere har vi kun oprettet Mønster objekter på en grundlæggende måde. Denne klasse har dog en anden variant af udarbejde metode, der accepterer et sæt flag sammen med regex-argumentet, der påvirker måden, hvorpå mønsteret matches.

Disse flag er simpelthen abstrakte heltalværdier. Lad os overbelaste runTest metode i testklassen, så den kan tage et flag som det tredje argument:

offentlig statisk int runTest (String regex, String text, int flags) {mønster = Pattern.compile (regex, flags); matcher = mønster. matcher (tekst); int matches = 0; mens (matcher.find ()) {matcher ++; } returnere kampe }

I dette afsnit vil vi se på de forskellige understøttede flag og hvordan de bruges.

Mønster.CANON_EQ

Dette flag muliggør kanonisk ækvivalens. Når det er angivet, anses to tegn for at matche, hvis og kun hvis deres fulde kanoniske nedbrydning stemmer overens.

Overvej den accenterede Unicode-karakter é. Dens sammensatte kodepunkt er u00E9. Unicode har imidlertid også et separat kodepunkt for dets komponenttegn e, u0065 og den akutte accent, u0301. I dette tilfælde sammensat karakter u00E9 kan ikke skelnes fra de to tegn sekvenser u0065 u0301.

Som standard tager matchning ikke hensyn til kanonisk ækvivalens:

@Test offentligt ugyldigt givetRegexWithoutCanonEq_whenMatchFailsOnEquivalentUnicode_thenCorrect () {int matches = runTest ("\ u00E9", "\ u0065 \ u0301"); assertFalse (matches> 0); }

Men hvis vi tilføjer flag, så vil testen bestå:

@Test offentlig ugyldighed givenRegexWithCanonEq_whenMatchesOnEquivalentUnicode_thenCorrect () {int matches = runTest ("\ u00E9", "\ u0065 \ u0301", Pattern.CANON_EQ); assertTrue (matches> 0); }

Mønster.CASE_INSENSITIVE

Dette flag muliggør matchning uanset sag. Som standard tages der hensyn til matchning:

@Test offentligt ugyldigt givenRegexWithDefaultMatcher_whenMatchFailsOnDifferentCases_thenCorrect () {int matches = runTest ("dog", "This is a Dog"); assertFalse (matches> 0); }

Så ved hjælp af dette flag kan vi ændre standardadfærden:

@Test offentligt ugyldigt givenRegexWithCaseInsensitiveMatcher _whenMatchesOnDifferentCases_thenCorrect () {int matches = runTest ("dog", "This is a Dog", Pattern.CASE_INSENSITIVE); assertTrue (matches> 0); }

Vi kan også bruge det tilsvarende, indlejrede flagudtryk for at opnå det samme resultat:

@Test offentlig ugyldighed givenRegexWithEmbeddedCaseInsensitiveMatcher _whenMatchesOnDifferentCases_thenCorrect () {int matches = runTest ("(? I) dog", "This is a Dog"); assertTrue (matches> 0); }

Mønster KOMMENTARER

Java API giver en mulighed for at inkludere kommentarer ved hjælp af # i regex. Dette kan hjælpe med at dokumentere kompleks regex, der muligvis ikke umiddelbart er åbenbar for en anden programmør.

Kommentarflaget får matcheren til at ignorere ethvert hvidt mellemrum eller kommentarer i regexen og kun overveje mønsteret. I standardtilpasningstilstand mislykkedes følgende test:

@Test offentligt ugyldigt givetRegexWithComments_whenMatchFailsWithoutFlag_thenCorrect () {int matches = runTest ("dog $ #check for word dog at end of text", "This is a dog"); assertFalse (matches> 0); }

Dette skyldes, at matcheren vil se efter hele regex i inputteksten, inklusive mellemrum og # -tegnet. Men når vi bruger flag, ignorerer det de ekstra mellemrum, og hver tekst, der starter med #, ses som en kommentar, der skal ignoreres for hver linje:

@Test offentlig ugyldig givenRegexWithComments_whenMatchesWithFlag_thenCorrect () {int matches = runTest ("dog $ #check end of text", "This is a dog", Pattern.COMMENTS); assertTrue (matches> 0); }

Der er også et alternativt indlejret flagudtryk til dette:

@Test offentlig ugyldighed givenRegexWithComments_whenMatchesWithEmbeddedFlag_thenCorrect () {int matches = runTest ("(? X) dog $ #check end of text", "This is a dog"); assertTrue (matches> 0); }

Mønster. DOTALL

Som standard, når vi bruger prikken "." udtryk i regex, matcher vi alle tegn i input Snor indtil vi møder en ny linjekarakter.

Ved hjælp af dette flag vil kampen også omfatte linjeterminatoren. Vi vil forstå bedre med følgende eksempler. Disse eksempler vil være lidt anderledes. Da vi er interesseret i at hævde mod det matchede Snor, vi bruger matcher'S gruppe metode, der returnerer den forrige kamp.

For det første vil vi se standardadfærden:

@Test offentlig ugyldighed givenRegexWithLineTerminator_whenMatchFails_thenCorrect () {Mønster mønster = Mønster.kompil ("(. *)"); Matcher matcher = pattern.matcher ("dette er en tekst" + System.getProperty ("line.separator") + "fortsat på en anden linje"); matcher.find (); assertEquals ("dette er en tekst", matcher.group (1)); }

Som vi kan se, matches kun den første del af indgangen før linjeterminatoren.

Nu inde dotall tilstand, vil hele teksten inklusive linjeterminatoren blive matchet:

@Test offentlig ugyldighed givetRegexWithLineTerminator_whenMatchesWithDotall_thenCorrect () {Mønster mønster = Mønster.kompil ("(. *)", Mønster.DOTALL); Matcher matcher = pattern.matcher ("dette er en tekst" + System.getProperty ("line.separator") + "fortsat på en anden linje"); matcher.find (); assertEquals ("dette er en tekst" + System.getProperty ("line.separator") + "fortsat på en anden linje", matcher.group (1)); }

Vi kan også bruge et indlejret flagudtryk til at aktivere dotall mode:

@Test offentligt ugyldigt givenRegexWithLineTerminator_whenMatchesWithEmbeddedDotall _thenCorrect () {Mønster mønster = Mønster.kompil ("(? S) (. *)"); Matcher matcher = pattern.matcher ("dette er en tekst" + System.getProperty ("line.separator") + "fortsat på en anden linje"); matcher.find (); assertEquals ("dette er en tekst" + System.getProperty ("line.separator") + "fortsatte på en anden linje", matcher.group (1)); }

Mønster. LITERAL

I denne tilstand giver matcher ingen særlig betydning til metategn, escape-tegn eller regex-syntaks. Uden dette flag matcher matcheren følgende regex mod ethvert input Snor:

@Test offentligt ugyldigt givetRegex_whenMatchesWithoutLiteralFlag_thenCorrect () {int matches = runTest ("(. *)", "Text"); assertTrue (matches> 0); }

Dette er den standardadfærd, vi har set i alle eksemplerne. Men med dette flag vil der ikke blive fundet noget match, da matcheren vil lede efter (.*) i stedet for at fortolke det:

@Test offentligt ugyldigt givetRegex_whenMatchFailsWithLiteralFlag_thenCorrect () {int matches = runTest ("(. *)", "Text", Pattern.LITERAL); assertFalse (matches> 0); }

Hvis vi nu tilføjer den krævede streng, vil testen bestå:

@Test offentligt ugyldigt givetRegex_whenMatchesWithLiteralFlag_thenCorrect () {int matches = runTest ("(. *)", "Text (. *)", Pattern.LITERAL); assertTrue (matches> 0); }

Der er intet indlejret flagtegn til aktivering af bogstavelig parsing.

Mønster

Som standard ^ og $ metategn matcher absolut i henholdsvis begyndelsen og slutningen af ​​hele input Snor. Matcheren ser bort fra linjeterminatorer:

@Test offentlig ugyldighed givenRegex_whenMatchFailsWithoutMultilineFlag_thenCorrect () {int matches = runTest ("dog $", "This is a dog" + System.getProperty ("line.separator") + "dette er en ræv"); assertFalse (matches> 0); }

Kampen mislykkes, fordi matcheren søger efter hund i slutningen af ​​hele Snor men hund er til stede i slutningen af ​​strengens første linje.

Imidlertid, med flag, vil den samme test bestå, da matcheren nu tager højde for linjeterminatorer. Så strengen hund findes lige før linjen slutter, deraf succes:

@Test offentligt ugyldigt givenRegex_whenMatchesWithMultilineFlag_thenCorrect () {int matches = runTest ("dog $", "This is a dog" + System.getProperty ("line.separator") + "dette er en ræv", Pattern.MULTILINE); assertTrue (matches> 0); }

Her er den indlejrede flagversion:

@Test offentlig ugyldighed givenRegex_whenMatchesWithEmbeddedMultilineFlag_ thenCorrect () {int matches = runTest ("(? M) dog $", "This is a dog" + System.getProperty ("line.separator") + "dette er en ræv"); assertTrue (matches> 0); }

12. Matcher-klassemetoder

I dette afsnit vil vi se på nogle nyttige metoder til Matcher klasse. Vi grupperer dem efter funktionalitet for klarhedens skyld.

12.1. Indeksmetoder

Indeksmetoder giver nyttige indeksværdier, der viser nøjagtigt, hvor matchet blev fundet i input Snor . I den følgende test bekræfter vi start- og slutindeks for kampen for hund i input Snor :

@Test offentlig ugyldighed givenMatch_whenGetsIndices_thenCorrect () {Mønster mønster = Mønster.kompil ("hund"); Matcher matcher = pattern.matcher ("Denne hund er min"); matcher.find (); assertEquals (5, matcher.start ()); assertEquals (8, matcher.end ()); }

12.2. Undersøgelsesmetoder

Studiemetoder gennemgår input Snor og returner en boolsk, der angiver, om mønsteret findes. Almindeligt anvendte er Tændstikker og ser på metoder.

Det Tændstikker og ser på metoder begge forsøger at matche en indgangssekvens mod et mønster. Forskellen er, at Tændstikker kræver, at hele indgangssekvensen matches, mens ser på gør ikke.

Begge metoder starter i begyndelsen af ​​input Snor :

@Test offentlig ugyldigt nårStudyMethodsWork_thenCorrect () {Mønster mønster = Mønster.kompil ("hund"); Matcher matcher = pattern.matcher ("hunde er venlige"); assertTrue (matcher.lookingAt ()); assertFalse (matcher.matches ()); }

Kampmetoden returneres sandt i en sag som sådan:

@Test offentlig ugyldigt nårMatchesStudyMethodWorks_thenCorrect () {Mønster mønster = Mønster.kompil ("hund"); Matcher matcher = pattern.matcher ("hund"); assertTrue (matcher.matches ()); }

12.3. Udskiftningsmetoder

Erstatningsmetoder er nyttige til at erstatte tekst i en inputstreng. De almindelige er erstatte første og udskift alle.

Det erstatte første og udskift alle metoder erstatter teksten, der matcher et givet regulært udtryk. Som deres navne indikerer, erstatte første erstatter den første forekomst, og udskift alle erstatter alle forekomster:

@Test offentligt ugyldigt nårReplaceFirstWorks_thenCorrect () {Mønster mønster = Mønster.kompil ("hund"); Matcher matcher = pattern.matcher ("hunde er husdyr, hunde er venlige"); Streng newStr = matcher.replaceFirst ("kat"); assertEquals ("katte er husdyr, hunde er venlige", newStr); }

Erstat alle forekomster:

@Test offentlig ugyldig nårReplaceAllWorks_thenCorrect () {Mønster mønster = Mønster.kompil ("hund"); Matcher matcher = pattern.matcher ("hunde er husdyr, hunde er venlige"); Streng newStr = matcher.replaceAll ("kat"); assertEquals ("katte er husdyr, katte er venlige", newStr); }

Det udskift alle metode giver os mulighed for at erstatte alle kampe med den samme erstatning. Hvis vi ønsker at udskifte tændstikker fra sag til sag, har vi brug for en udskiftningsteknik for token.

13. Konklusion

I denne artikel har vi lært, hvordan man bruger regulære udtryk i Java, og også udforsket de vigtigste funktioner i java.util.regex pakke.

Den fulde kildekode til projektet inklusive alle de kodeeksempler, der bruges her, kan findes i GitHub-projektet.