Vodič kroz API za regularne izraze Java

1. Pregled

U ovom ćemo članku razmotriti Java Regex API i kako se regularni izrazi mogu koristiti u Java programskom jeziku.

U svijetu regularnih izraza možete izabrati mnogo različitih okusa, poput grep, Perl, Python, PHP, awk i još mnogo toga.

To znači da regularni izraz koji radi na jednom programskom jeziku možda neće raditi na drugom. Sintaksa regularnog izraza u Javi najsličnija je onoj koja se nalazi u Perlu.

2. Postavljanje

Da bismo koristili regularne izraze u Javi, ne trebaju nam posebne postavke. JDK sadrži poseban paket java.util.regex potpuno posvećen operacijama regularnih izraza. Trebamo ga samo uvesti u naš kod.

Štoviše, java.lang.String class također ima ugrađenu podršku za regex koji obično koristimo u našem kodu.

3. Java Regex paket

The java.util.regex paket se sastoji od tri klase: Uzorak, Matcher i PatternSyntaxException:

  • Uzorak objekt je sastavljeni regularni izraz. The Uzorak klasa ne pruža javne konstruktore. Da bismo stvorili uzorak, prvo moramo prizvati jednu njegovu javnu statiku sastaviti metode, koje će zatim vratiti a Uzorak objekt. Ove metode prihvaćaju regularni izraz kao prvi argument.
  • Podudaranje objekt interpretira uzorak i izvodi operacije podudaranja protiv ulaza Niz. Također ne definira nikakve javne konstruktore. Dobivamo a Podudaranje objekt pozivanjem na podudaranje metoda na a Uzorak objekt.
  • PatternSyntaxException object je neprovjerena iznimka koja ukazuje na sintaksnu pogrešku u uzorku regularnog izraza.

Detaljno ćemo istražiti ove satove; međutim, prvo moramo shvatiti kako se regex konstruira u Javi.

Ako ste već upoznati s regularnim izrazima iz drugog okruženja, možda ćete pronaći određene razlike, ali one su minimalne.

4. Jednostavan primjer

Počnimo s najjednostavnijim slučajem upotrebe regularnog izraza. Kao što smo ranije primijetili, kada se regularni izraz primijeni na niz, može se podudarati s nula ili više puta.

Najosnovniji oblik podudaranja uzoraka koji podržava java.util.regex API je utakmica a Niz doslovno. Na primjer, ako je regularni izraz foo i ulaz Niz je foo, utakmica će uspjeti jer Žice su identični:

@Test javna praznina givenText_whenSimpleRegexMatches_thenCorrect () {Pattern pattern = Pattern.compile ("foo"); Podudaranje podudaranje = pattern.matcher ("foo"); assertTrue (matcher.find ()); }

Prvo stvorimo a Uzorak objekt pozivanjem njegove statičke sastaviti metodu i prosljeđivanje uzorka koji želimo koristiti.

Tada kreiramo Podudaranje objekt koji poziva Uzorak objekt podudaranje metodu i prosljeđujući joj tekst koji želimo provjeriti radi podudaranja.

Nakon toga nazivamo metodu pronaći u objektu Matcher.

The pronaći metoda nastavlja napredovati kroz ulazni tekst i vraća true za svako podudaranje, tako da ga možemo koristiti i za pronalaženje broja podudaranja:

@Test javna praznina givenText_whenSimpleRegexMatchesTwice_thenCorrect () {Pattern pattern = Pattern.compile ("foo"); Podudaranje podudaranja = pattern.matcher ("foofoo"); int odgovara = 0; while (matcher.find ()) {odgovara ++; } assertEquals (podudaranja, 2); }

Budući da ćemo izvoditi više testova, možemo apstrahirati logiku za pronalaženje broja podudaranja u tzv runTest:

javni statički int runTest (String regex, String text) {Pattern pattern = Pattern.compile (regex); Podudaranje podudaranja = pattern.matcher (tekst); int odgovara = 0; while (matcher.find ()) {odgovara ++; } uzvratne utakmice; }

Kad dobijemo 0 podudaranja, test bi trebao pasti, u protivnom bi trebao proći.

5. Meta likovi

Meta znakovi utječu na način na koji se uzorku podudara, na način koji dodaje logiku uzorku pretraživanja. Java API podržava nekoliko metaznakova, od kojih je najizravnija točka “.” koji odgovara bilo kojem liku:

@Test javna praznina givenText_whenMatchesWithDotMetach_thenCorrect () {int odgovara = runTest (".", "Foo"); assertTrue (podudara se> 0); }

Uzimajući u obzir prethodni primjer gdje je regex foo odgovarao tekstu foo kao i foofoo Dva puta. Da smo koristili metaznak točkica u regularnom izrazu, u drugom slučaju ne bismo dobili dva podudaranja:

@Test javna praznina givenRepeatedText_whenMatchesOnceWithDotMetach_thenCorrect () {int odgovara = runTest ("foo.", "Foofoo"); assertEquals (podudaranja, 1); }

Primijetite točku iza foo u regularnom izrazu. Podudaranje odgovara svakom tekstu kojem prethodi foo budući da zadnji dio točke znači bilo koji znak nakon. Pa nakon pronalaska prvog foo, na ostatak se gleda kao na bilo koji lik. Zbog toga postoji samo jedan meč.

API podržava nekoliko drugih meta znakova koje ćemo dalje razmotriti u ovom članku.

6. Razredi likova

Pregledavanje službenog Uzorak specifikacija klase, otkrit ćemo sažetke podržanih konstrukcija regularnih izraza. Pod klasama znakova imamo oko 6 konstrukata.

6.1. ILI Razred

Izgrađen kao [abc]. Podudara se bilo koji od elemenata u skupu:

@Test public void givenORSet_whenMatchesAny_thenCorrect () {int matches = runTest ("[abc]", "b"); assertEquals (podudaranja, 1); }

Ako se svi pojave u tekstu, svaki se podudara zasebno, bez obzira na redoslijed:

@Test javna praznina givenORSet_whenMatchesAnyAndAll_thenCorrect () {int matches = runTest ("[abc]", "cab"); assertEquals (utakmice, 3); }

Također se mogu izmjenjivati ​​kao dio a Niz. U sljedećem primjeru, kada stvaramo različite riječi izmjenjujući prvo slovo sa svakim elementom skupa, sve se podudaraju:

@Test javna praznina givenORSet_whenMatchesAllCombinations_thenCorrect () {int matches = runTest ("[bcr] at", "bat cat rat"); assertEquals (utakmice, 3); }

6.2. NI Razred

Gornji skup negira se dodavanjem znaka kao prvog elementa:

@Test javna praznina danaNORSet_whenMatchesNon_thenCorrect () {int odgovara = runTest ("[^ abc]", "g"); assertTrue (podudara se> 0); }

Još jedan slučaj:

@Test javna praznina danaNORSet_whenMatchesAllExceptElements_thenCorrect () {int matches = runTest ("[^ bcr] at", "sat mat eat"); assertTrue (podudara se> 0); }

6.3. Klasa dometa

Možemo definirati klasu koja određuje raspon unutar kojeg bi podudarni tekst trebao pasti pomoću crtice (-), isto tako, možemo i negirati raspon.

Podudaranje velikih slova:

@Test javna praznina givenUpperCaseRange_whenMatchesUpperCase_ thenCorrect () {int matches = runTest ("[A-Z]", "Dvije velike abecede 34 ukupno"); assertEquals (utakmice, 2); }

Podudaranje malih slova:

@Test javna praznina givenLowerCaseRange_whenMatchesLowerCase_ thenCorrect () {int matches = runTest ("[a-z]", "Dvije velike abecede 34 ukupno"); assertEquals (utakmice, 26); }

Usklađivanje velikih i malih slova:

@Test javna praznina givenBothLowerAndUpperCaseRange_ whenMatchesAllLetters_thenCorrect () {int matches = runTest ("[a-zA-Z]", "Dvije velike abecede 34 ukupno"); assertEquals (utakmice, 28); }

Podudaranje određenog raspona brojeva:

@Test javna praznina givenNumberRange_whenMatchesAccurately_ thenCorrect () {int matches = runTest ("[1-5]", "Dvije velike abecede 34 ukupno"); assertEquals (utakmice, 2); }

Podudaranje s drugim rasponom brojeva:

@Test javna praznina givenNumberRange_whenMatchesAccurately_ thenCorrect2 () {int matches = runTest ("[30-35]", "Dvije velike abecede 34 ukupno"); assertEquals (podudaranja, 1); }

6.4. Union Class

Klasa sindikalnih znakova rezultat je kombiniranja dviju ili više klasa znakova:

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

Gornji test podudarat će se samo s 6 od 9 cijelih brojeva jer skup sindikata preskače 4, 5 i 6.

6.5. Razred presijecanja

Slično klasi unije, i ova klasa nastaje odabirom zajedničkih elemenata između dva ili više skupova. Za primjenu raskrižja koristimo &&:

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

Dobivamo 4 podudaranja jer presjek dva seta ima samo 4 elementa.

6.6. Klasa oduzimanja

Oduzimanje možemo koristiti za negiranje jedne ili više klasa znakova, na primjer podudaranje skupa neparnih decimalnih brojeva:

@Test javna praznina givenSetWithSubtraction_whenMatchesAccurately_thenCorrect () {int odgovara = runTest ("[0-9 && [^ 2468]]", "123456789"); assertEquals (utakmice, 5); }

Samo 1,3,5,7,9 bit će podudarni.

7. Unaprijed definirane klase znakova

Java regex API također prihvaća unaprijed definirane klase znakova. Neke od gore navedenih klasa znakova mogu se izraziti u kraćem obliku, mada čine kôd manje intuitivnim. Jedan poseban aspekt Java verzije ovog regularnog izraza je znak za bijeg.

Kao što ćemo vidjeti, većina znakova započet će kosom crtom koja u Javi ima posebno značenje. Da bi ih sastavio Uzorak klasa - mora se izbjeći vodeća kosa crtica tj. \ d postaje \ d.

Brojke koje odgovaraju, ekvivalentno [0-9]:

@Test javna praznina givenDigits_whenMatches_thenCorrect () {int matches = runTest ("\ d", "123"); assertEquals (utakmice, 3); }

Podudaranje ne-znamenki, ekvivalentno [^0-9]:

@Test javna praznina givenNonDigits_whenMatches_thenCorrect () {int mathces = runTest ("\ D", "a6c"); assertEquals (utakmice, 2); }

Odgovarajući razmak:

@Test javna praznina givenWhiteSpace_whenMatches_thenCorrect () {int odgovara = runTest ("\ s", "a c"); assertEquals (podudaranja, 1); }

Podudaranje s bijelim razmakom:

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

Podudaranje znaka riječi, ekvivalentno [a-zA-Z_0-9]:

@Test javna praznina givenWordCharacter_whenMatches_thenCorrect () {int matches = runTest ("\ w", "hi!"); assertEquals (utakmice, 2); }

Podudaranje znaka koji nije riječ:

@Test javna praznina givenNonWordCharacter_whenMatches_thenCorrect () {int matches = runTest ("\ W", "hi!"); assertEquals (podudaranja, 1); }

8. Kvantifikatori

Java regex API također nam omogućuje upotrebu kvantifikatora. Oni nam omogućuju daljnje prilagođavanje ponašanja podudaranja određivanjem broja pojava protiv kojih se mora podudarati.

Da bismo uskladili tekst s nulom ili jednom, koristimo ? kvantifikator:

@Test javna praznina givenZeroOrOneQuantifier_whenMatches_thenCorrect () {int matches = runTest ("\ a?", "Hi"); assertEquals (utakmice, 3); }

Alternativno, možemo koristiti sintaksu zagrada, također podržanu od Java regex API-ja:

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

Ovaj primjer uvodi koncept podudaranja nulte duljine. Dogodi se tako da ako je prag kvantifikatora za podudaranje jednak nuli, uvijek se podudara sa svime u tekstu, uključujući prazno Niz na kraju svakog unosa. To znači da će, čak i ako je ulaz prazan, vratiti jedno podudaranje nulte duljine.

To objašnjava zašto u gore navedenom primjeru dobivamo 3 podudaranja unatoč tome što imamo String duljine dvije. Treće podudaranje je prazno nulte duljine Niz.

Da bi se tekst podudarao s nulom ili bez ograničenja, mi * koristimo kvantifikator, on je sličan?:

@Test javna praznina givenZeroOrManyQuantifier_whenMatches_thenCorrect () {int odgovara = runTest ("\ a *", "hi"); assertEquals (utakmice, 3); }

Podržana alternativa:

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

Kvantifikator s razlikom je +, ima prag podudaranja 1. Ako je potrebno Niz uopće ne dogodi, neće biti podudaranja, čak ni nulte duljine Niz:

@Test javna praznina givenOneOrManyQuantifier_whenMatches_thenCorrect () {int odgovara = runTest ("\ a +", "hi"); assertFalse (podudaranja); }

Podržana alternativa:

@Test javna praznina givenOneOrManyQuantifier_whenMatches_thenCorrect2 () {int matches = runTest ("\ a {1,}", "hi"); assertFalse (podudaranja); }

Kao što je to u Perlu i drugim jezicima, sintaksa zagrada može se koristiti za podudaranje određenog teksta nekoliko puta:

@Test javna praznina givenBraceQuantifier_whenMatches_thenCorrect () {int matches = runTest ("a {3}", "aaaaaa"); assertEquals (utakmice, 2); }

U gornjem primjeru dobivamo dvije podudarnosti budući da se podudaranje događa samo ako a pojavljuje se tri puta zaredom. Međutim, u sljedećem testu nećemo dobiti podudaranje jer se tekst pojavljuje samo dva puta zaredom:

@Test javna praznina givenBraceQuantifier_whenFailsToMatch_thenCorrect () {int odgovara = runTest ("a {3}", "aa"); assertFalse (podudara se> 0); }

Kada koristimo raspon u zagradama, podudaranje će biti pohlepno, podudarajući se s gornjeg kraja raspona:

@Test javna praznina givenBraceQuantifierWithRange_whenMatches_thenCorrect () {int odgovara = runTest ("a {2,3}", "aaaa"); assertEquals (podudaranja, 1); }

Naveli smo najmanje dvije pojave, ali ne više od tri, tako da umjesto toga dobivamo jedan meč tamo gdje meč vidi jedan aaa i a usamljeni a kojem se ne može mjeriti.

Međutim, API nam omogućuje da odredimo lijeni ili nevoljki pristup tako da podudaranje može započeti s donjeg kraja raspona, u kojem slučaju podudaranje dvije pojave kao aa i aa:

@Test javna praznina givenBraceQuantifierWithRange_whenMatchesLazily_thenCorrect () {int odgovara = runTest ("a {2,3}?", "Aaaa"); assertEquals (utakmice, 2); }

9. Hvatanje grupa

API nam također omogućuje tretirati više znakova kao jednu jedinicu kroz skupine za hvatanje.

Pridružit će brojeve skupinama za hvatanje i omogućiti povratno pozivanje pomoću tih brojeva.

U ovom ćemo odjeljku vidjeti nekoliko primjera kako koristiti skupine za hvatanje u API-ju Java regex.

Upotrijebimo skupinu za hvatanje koja se podudara samo kad ulazni tekst sadrži dvije znamenke jedna pored druge:

@Test javna praznina givenCapturingGroup_whenMatches_thenCorrect () {int maches = runTest ("(\ d \ d)", "12"); assertEquals (podudaranja, 1); }

Broj priložen uz gornju podudarnost je 1, koristeći povratnu referencu kako bismo podudaraču rekli da želimo upariti još jednu pojavu podudarnog dijela teksta. Na ovaj način, umjesto:

@Test javna praznina givenCapturingGroup_whenMatches_thenCorrect2 () {int matches = runTest ("(\ d \ d)", "1212"); assertEquals (utakmice, 2); }

Tamo gdje postoje dva odvojena podudaranja za ulaz, možemo imati jedno podudaranje, ali šireći isto podudaranje regularnog izraza kako bi obuhvatilo cijelu duljinu unosa koristeći povratno referenciranje:

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

Gdje bismo morali ponoviti regularni izraz bez povratnih referenci da bismo postigli isti rezultat:

@Test javna praznina givenCapturingGroup_whenMatches_thenCorrect3 () {int matches = runTest ("(\ d \ d) (\ d \ d)", "1212"); assertEquals (podudaranja, 1); }

Slično tome, za bilo koji drugi broj ponavljanja, povratno upućivanje može učiniti da uparivač vidi ulaz kao jedno podudaranje:

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

Ali ako promijenite čak i zadnju znamenku, podudaranje neće uspjeti:

@Test javna praznina givenCapturingGroupAndWrongInput_ whenMatchFailsWithBackReference_thenCorrect () {int matches = runTest ("(\ d \ d) \ 1", "1213"); assertFalse (podudara se> 0); }

Važno je ne zaboraviti povratne kose crte u bijegu, to je presudno u sintaksi Java.

10. Podudaranje granica

Java regex API također podržava podudaranje granica. Ako nas zanima gdje bi se točno u ulaznom tekstu trebalo podudarati, to je ono što tražimo. S prethodnim primjerima bilo nam je svejedno je li pronađeno podudaranje ili nije.

Za podudaranje samo kada je traženi regularni izraz istinit na početku teksta, koristimo kazaljku ^.

Ovaj test neće uspjeti od teksta pas možete pronaći na početku:

@Test javna praznina givenText_whenMatchesAtBeginning_thenCorrect () {int matches = runTest ("^ pas", "psi su prijateljski raspoloženi"); assertTrue (podudara se> 0); }

Sljedeći test neće uspjeti:

@Test javna praznina givenTextAndWrongInput_whenMatchFailsAtBeginning_ thenCorrect () {int matches = runTest ("^ dog", "jesu li psi prijateljski nastrojeni?"); assertFalse (podudara se> 0); }

Za podudaranje samo kada je traženi regularni izraz istinit na kraju teksta, koristimo znak dolar $. Podudaranje će se naći u sljedećem slučaju:

@Test javna praznina givenText_whenMatchesAtEnd_thenCorrect () {int matches = runTest ("dog $", "Čovjekov najbolji prijatelj je pas"); assertTrue (podudara se> 0); }

I ovdje neće biti pronađeno podudaranje:

@Test javna praznina givenTextAndWrongInput_whenMatchFailsAtEnd_thenCorrect () {int matches = runTest ("pas $", "je li pasji čovjek najbolji prijatelj?"); assertFalse (podudara se> 0); }

Ako želimo podudaranje samo kada se traženi tekst pronađe na granici riječi, koristimo \ b regularni izraz na početku i na kraju regularnog izraza:

Prostor je granica riječi:

@Test javna praznina givenText_whenMatchesAtWordBoundary_thenCorrect () {int matches = runTest ("\ bdog \ b", "pas je prijateljski raspoložen"); assertTrue (podudara se> 0); }

Prazni niz na početku retka također je granica riječi:

@Test javna praznina givenText_whenMatchesAtWordBoundary_thenCorrect2 () {int matches = runTest ("\ bdog \ b", "pas je čovjekov najbolji prijatelj"); assertTrue (podudara se> 0); }

Ovi testovi prolaze jer je početak a Niz, kao i razmak između jednog i drugog teksta, označava granicu riječi, međutim, sljedeći test pokazuje suprotno:

@Test javna praznina givenWrongText_whenMatchFailsAtWordBoundary_thenCorrect () {int matches = runTest ("\ bdog \ b", "snoop dogg je reper"); assertFalse (podudara se> 0); }

Znakovi od dvije riječi koji se pojavljuju u redu ne označavaju granicu riječi, ali možemo je proći tako da promijenimo kraj regularnog izraza kako bi se tražila granica koja nije riječ:

@Test javna praznina givenText_whenMatchesAtWordAndNonBoundary_thenCorrect () {int matches = runTest ("\ bdog \ B", "snoop dogg je reper"); assertTrue (podudara se> 0); }

11. Metode klase uzoraka

Prije smo samo stvarali Uzorak predmeta na osnovni način. Međutim, ova klasa ima još jednu varijantu sastaviti metoda koja prihvaća skup zastavica uz argument regularnog izraza koji utječu na način podudaranja s uzorkom.

Te su zastave jednostavno apstrahirane cjelobrojne vrijednosti. Preopteretimo runTest metoda u testnoj klasi tako da može uzeti zastavicu kao treći argument:

javni statički int runTest (string regularni izraz, tekst niza, int zastave) {pattern = Pattern.compile (regularni izraz, zastave); podudaranje = uzorak.matcher (tekst); int odgovara = 0; while (matcher.find ()) {odgovara ++; } uzvratne utakmice; }

U ovom ćemo odjeljku pogledati različite podržane zastave i kako se koriste.

Uzorak.CANON_EQ

Ova zastava omogućuje kanonsku ekvivalentnost. Kada se navede, smatrat će se da se dva znaka podudaraju ako i samo ako se podudaraju njihove pune kanonske dekompozicije.

Razmotrite naglašeni Unicode znak é. Njegova kompozitna kodna točka je u00E9. Međutim, Unicode također ima zasebnu kodnu točku za svoje sastavne znakove e, u0065 i akutni naglasak, u0301. U ovom slučaju, složeni znak u00E9 se ne razlikuje od niza od dva znaka u0065 u0301.

Prema zadanim postavkama, podudaranje ne uzima u obzir kanonsku ekvivalentnost:

@Test javna praznina givenRegexWithoutCanonEq_whenMatchFailsOnEquivalentUnicode_thenCorrect () {int odgovara = runTest ("\ u00E9", "\ u0065 \ u0301"); assertFalse (podudara se> 0); }

Ali ako dodamo zastavicu, tada će test proći:

@Test javna praznina givenRegexWithCanonEq_whenMatchesOnEquivalentUnicode_thenCorrect () {int odgovara = runTest ("\ u00E9", "\ u0065 \ u0301", Pattern.CANON_EQ); assertTrue (podudara se> 0); }

Uzorak.CASE_INSENSITIVE

Ova zastavica omogućuje podudaranje bez obzira na slučaj. Prema zadanim postavkama podudaranje uzima u obzir velika i mala slova:

@Test javna praznina givenRegexWithDefaultMatcher_whenMatchFailsOnDifferentCases_thenCorrect () {int matches = runTest ("dog", "Ovo je pas"); assertFalse (podudara se> 0); }

Dakle, pomoću ove zastavice možemo promijeniti zadano ponašanje:

@Test javna praznina givenRegexWithCaseInsensitiveMatcher _whenMatchesOnDifferentCases_thenCorrect () {int matches = runTest ("dog", "Ovo je pas", Pattern.CASE_INSENSITIVE); assertTrue (podudara se> 0); }

Također možemo koristiti ekvivalentni, ugrađeni izraz zastave kako bismo postigli isti rezultat:

@Test javna praznina givenRegexWithEmbeddedCaseInsensitiveMatcher _whenMatchesOnDifferentCases_thenCorrect () {int matches = runTest ("(? I) dog", "Ovo je pas"); assertTrue (podudara se> 0); }

Uzorak.KOMENTARI

Java API omogućuje uključivanje komentara pomoću # u regex. To može pomoći u dokumentiranju složenog regularnog izraza koji nekom programeru možda neće biti odmah očit.

Oznaka komentara čini da podudarnik ignorira razmake ili komentare u regularnom izrazu i uzima u obzir samo obrazac. U zadanom načinu podudaranja sljedeći test neće uspjeti:

@Test javna praznina givenRegexWithComments_whenMatchFailsWithoutFlag_thenCorrect () {int matches = runTest ("dog $ #check za riječ dog na kraju teksta", "Ovo je pas"); assertFalse (podudara se> 0); }

To je zato što će podudarnik tražiti cjelokupni regularni izraz u ulaznom tekstu, uključujući razmake i znak #. Ali kada upotrijebimo zastavicu, ona će zanemariti dodatne razmake, a svaki tekst koji započinje s # smatrat će se komentarom koji se zanemaruje za svaki redak:

@Test javna praznina givenRegexWithComments_whenMatchesWithFlag_thenCorrect () {int matches = runTest ("pas $ #check kraj teksta", "Ovo je pas", Pattern.COMMENTS); assertTrue (podudara se> 0); }

Za to postoji i alternativni ugrađeni izraz zastave:

@Test javna praznina givenRegexWithComments_whenMatchesWithEmbeddedFlag_thenCorrect () {int matches = runTest ("(? X) dog $ #check kraj teksta", "Ovo je pas"); assertTrue (podudara se> 0); }

Uzorak.DOTAL

Prema zadanim postavkama, kada koristimo točku "." Izraz u regularnom izrazu, podudaramo svaki znak u ulazu Niz sve dok ne naiđemo na novi linijski lik.

Koristeći ovu zastavicu, utakmica će također sadržavati i završnicu crte. Sljedeće ćemo primjere bolje razumjeti. Ovi će primjeri biti malo drugačiji. Budući da smo zainteresirani za tvrdnju protiv podudarnog Niz, koristit ćemo podudaranje‘S skupina metoda koja vraća prethodno podudaranje.

Prvo ćemo vidjeti zadano ponašanje:

@Test javna praznina givenRegexWithLineTerminator_whenMatchFails_thenCorrect () {Pattern pattern = Pattern.compile ("(. *)"); Podudaranje podudaranje = pattern.matcher ("ovo je tekst" + System.getProperty ("line.separator") + "nastavljeno na drugom retku"); podudaranje.find (); assertEquals ("ovo je tekst", matcher.group (1)); }

Kao što vidimo, podudara se samo prvi dio ulaza prije završivača linije.

Sada u dotall modu, podudarat će se cijeli tekst, uključujući završetak retka:

@Test javna praznina givenRegexWithLineTerminator_whenMatchesWithDotall_thenCorrect () {Pattern pattern = Pattern.compile ("(. *)", Pattern.DOTALL); Podudaranje podudaranje = pattern.matcher ("ovo je tekst" + System.getProperty ("line.separator") + "nastavljeno na drugom retku"); podudaranje.find (); assertEquals ("ovo je tekst" + System.getProperty ("line.separator") + "nastavio na drugom retku", matcher.group (1)); }

Za omogućavanje možemo koristiti i ugrađeni izraz zastave dotall način rada:

@Test javna praznina givenRegexWithLineTerminator_whenMatchesWithEmbeddedDotall _thenCorrect () {Pattern pattern = Pattern.compile ("(? S) (. *)"); Podudaranje podudaranje = pattern.matcher ("ovo je tekst" + System.getProperty ("line.separator") + "nastavljeno na drugom retku"); podudaranje.find (); assertEquals ("ovo je tekst" + System.getProperty ("line.separator") + "nastavio na drugom retku", matcher.group (1)); }

Uzorak.LITERALNO

Kada je u ovom načinu rada, podudaranje ne daje posebno značenje bilo kojim znakovima, izlaznim znakovima ili sintaksi regularnog izraza. Bez ove zastavice, podudaranje će se podudarati sa sljedećim regularnim izrazom protiv bilo kojeg unosa Niz:

@Test javna praznina givenRegex_whenMatchesWithoutLiteralFlag_thenCorrect () {int odgovara = runTest ("(. *)", "Text"); assertTrue (podudara se> 0); }

To je zadano ponašanje koje smo vidjeli u svim primjerima. Međutim, s ovom zastavicom neće biti pronađeno podudaranje, jer će onaj koji traži utakmicu tražiti (.*) umjesto da ga protumačite:

@Test javna praznina givenRegex_whenMatchFailsWithLiteralFlag_thenCorrect () {int odgovara = runTest ("(. *)", "Text", Pattern.LITERAL); assertFalse (podudara se> 0); }

Ako dodamo traženi niz, test će proći:

@Test javna praznina givenRegex_whenMatchesWithLiteralFlag_thenCorrect () {int matches = runTest ("(. *)", "Text (. *)", Pattern.LITERAL); assertTrue (podudara se> 0); }

Ne postoji ugrađeni znak zastavice za omogućavanje raščlanjivanja doslovnih podataka.

Uzorak.MULTILINE

Prema zadanim postavkama ^ i $ metaznaci se podudaraju apsolutno na početku odnosno na kraju cijelog unosa Niz. Podudaranje zanemaruje bilo koji završetak linije:

@Test javna praznina givenRegex_whenMatchFailsWithoutMultilineFlag_thenCorrect () {int matches = runTest ("dog $", "Ovo je pas" + System.getProperty ("line.separator") + "ovo je lisica"); assertFalse (podudara se> 0); }

Podudaranje ne uspije jer podudaranje traži pas na kraju cijelog Niz ali pas nalazi se na kraju prvog retka niza.

Međutim, s zastavicom će proći isti test budući da podudaranje sada uzima u obzir završne linije. Znači Niz pas nalazi se neposredno prije nego što linija završava, otuda i uspjeh:

@Test javna praznina givenRegex_whenMatchesWithMultilineFlag_thenCorrect () {int matches = runTest ("dog $", "Ovo je pas" + System.getProperty ("line.separator") + "ovo je lisica", Pattern.MULTILINE); assertTrue (podudara se> 0); }

Evo verzije ugrađene zastave:

@Test javna praznina givenRegex_whenMatchesWithEmbeddedMultilineFlag_ thenCorrect () {int matches = runTest ("(? M) dog $", "Ovo je pas" + System.getProperty ("line.separator") + "ovo je lisica"); assertTrue (podudara se> 0); }

12. Metode klase podudaranja

U ovom ćemo odjeljku pogledati neke korisne metode Podudaranje razred. Za preglednost ćemo ih grupirati prema funkcionalnosti.

12.1. Indeksne metode

Indeksne metode pružaju korisne vrijednosti indeksa koje točno pokazuju gdje je podudarnost pronađena na ulazu Niz . U sljedećem testu potvrdit ćemo indekse početka i završetka utakmice za pas u ulazu Niz :

@Test javna praznina givenMatch_whenGetsIndices_thenCorrect () {Pattern pattern = Pattern.compile ("dog"); Podudaranje podudaranje = pattern.matcher ("Ovaj pas je moj"); podudaranje.find (); assertEquals (5, matcher.start ()); assertEquals (8, matcher.end ()); }

12.2. Metode proučavanja

Metode proučavanja prolaze kroz ulazne podatke Niz i vratiti logičku vrijednost koja pokazuje da li je uzorak pronađen. Uobičajeno korišteni su šibice i gledati u metode.

The šibice i gledati u obje metode pokušavaju usporediti ulazni niz sa uzorkom. Razlika je u tome šibice zahtijeva podudaranje cijele sekvence unosa, dok gledati u ne.

Obje metode počinju na početku unosa Niz :

@Test public void whenStudyMethodsWork_thenCorrect () {Pattern pattern = Pattern.compile ("pas"); Podudaranje podudaranje = pattern.matcher ("psi su prijateljski raspoloženi"); assertTrue (matcher.lookingAt ()); assertFalse (matcher.matches ()); }

Metoda podudaranja vratit će vrijednost true u sljedećem slučaju:

@Test public void whenMatchesStudyMethodWorks_thenCorrect () {Pattern pattern = Pattern.compile ("pas"); Podudaranje podudaranje = pattern.matcher ("pas"); assertTrue (matcher.matches ()); }

12.3. Zamjenske metode

Zamjenske metode korisne su za zamjenu teksta u ulaznom nizu. One uobičajene su replaceFirst i zamjeni sve.

The replaceFirst i zamjeni sve metode zamjenjuju tekst koji odgovara zadanom regularnom izrazu. Kao što njihova imena pokazuju, replaceFirst zamjenjuje prvu pojavu i zamjeni sve zamjenjuje sve pojave:

@Test public void whenReplaceFirstWorks_thenCorrect () {Pattern pattern = Pattern.compile ("pas"); Podudaranje podudaranja = pattern.matcher ("psi su domaće životinje, psi su prijateljski raspoloženi"); Niz newStr = matcher.replaceFirst ("mačka"); assertEquals ("mačke su domaće životinje, psi su prijateljski raspoloženi", newStr); }

Zamijeni sve pojave:

@Test public void whenReplaceAllWorks_thenCorrect () {Pattern pattern = Pattern.compile ("pas"); Podudaranje podudaranja = pattern.matcher ("psi su domaće životinje, psi su prijateljski raspoloženi"); Niz newStr = matcher.replaceAll ("mačka"); assertEquals ("mačke su domaće životinje, mačke su prijateljske", newStr); }

The zamjeni sve metoda omogućuje nam da sve utakmice zamijenimo istom zamjenom. Ako želimo zamijeniti šibice za svaki slučaj posebno, trebat će nam tehnika zamjene žetona.

13. Zaključak

U ovom smo članku naučili kako koristiti regularne izraze u Javi, a također smo istražili najvažnije značajke java.util.regex paket.

Potpuni izvorni kod za projekt, uključujući sve ovdje korištene uzorke koda, može se naći u projektu GitHub.