Programovanie

Regulárne výrazy v Jave, časť 1: Porovnávanie vzorov a trieda vzorov

Triedy znakov a najrôznejších reťazcov Java ponúkajú nízkoúrovňovú podporu pre porovnávanie vzorov, ale táto podpora zvyčajne vedie ku komplexnému kódu. Pre jednoduchšie a efektívnejšie kódovanie ponúka Java Regex API. Tento dvojdielny návod vám pomôže začať s regulárnymi výrazmi a rozhraním Regex API. Najskôr rozbalíme tri výkonné triedy sídliace v java.util.regex balíček, potom preskúmame Vzor triedy a jej sofistikované konštrukcie zodpovedajúce vzorom.

stiahnuť Získajte kód Stiahnite si zdrojový kód napríklad pre aplikácie v tejto príručke. Vytvoril Jeff Friesen pre JavaWorld.

Čo sú regulárne výrazy?

A regulárny výraz, tiež známy ako a regulárny výraz alebo regexp, je reťazec, ktorého vzor (šablóna) popisuje sadu reťazcov. Vzor určuje, ktoré reťazce patria do množiny. Vzor sa skladá z doslovných znakov a metaznaky, čo sú znaky, ktoré majú namiesto doslovného významu špeciálny význam.

Zhoda vzorov je proces hľadania textu na identifikáciu zápasyalebo reťazce, ktoré zodpovedajú vzoru regulárneho výrazu. Java podporuje porovnávanie vzorov prostredníctvom svojho Regex API. API sa skladá z troch tried -Vzor, Matchera PatternSyntaxException--všetky umiestnené v java.util.regex balenie:

  • Vzor objekty, známe tiež ako vzory, sú kompilované regulárne výrazy.
  • Matcher predmety, príp dohadzovači, sú motory, ktoré interpretujú vzory na vyhľadanie zhôd v postupnosť znakov (objekty, ktorých triedy implementujú java.lang.CharSequence rozhranie a slúžia ako textové zdroje).
  • PatternSyntaxException objekty popisujú nelegálne vzory regulárneho výrazu.

Java tiež poskytuje podporu pre porovnávanie vzorov rôznymi spôsobmi java.lang.String trieda. Napríklad, boolovské zhody (reťazec regex) vracia sa pravda iba ak vyvolávajúci reťazec sa presne zhoduje regulárny výrazregulárny výraz.

Metódy pohodlia

V zákulisí, zápasy() a StringĎalšie pohodlné metódy zamerané na regulárny výraz sú implementované v rámci rozhrania Regex API.

RegexDemo

Vytvoril som RegexDemo aplikácia na demonštráciu regulárnych výrazov Java a rôznych metód nachádzajúcich sa v Vzor, Matchera PatternSyntaxException triedy. Tu je zdrojový kód ukážky:

Zoznam 1. Ukážka regexov

import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; public class RegexDemo {public static void main (String [] args) {if (args.length! = 2) {System.err.println ("use: java RegexDemo regex input"); návrat; } // Konvertuje sekvencie znakov nového riadku (\ n) na znaky nového riadku. args [1] = args [1] .replaceAll ("\ n", "\ n"); try {System.out.println ("regex =" + args [0]); System.out.println ("input =" + args [1]); Pattern p = Pattern.compile (args [0]); Matcher m = p.matcher (args [1]); while (m.find ()) System.out.println ("Nájdené [" + m.group () + "] začínajúce na„ + m.start () + "a končiace na„ + (m.end () - 1)); } catch (PatternSyntaxException pse) {System.err.println ("Zlý regex:" + pse.getMessage ()); System.err.println ("Popis:" + pse.getDescription ()); System.err.println ("Register:" + pse.getIndex ()); System.err.println ("Nesprávny vzor:" + pse.getPattern ()); }}}

Prvá vec RegexDemoje hlavný() metódou je overenie príkazového riadku. To si vyžaduje dva argumenty: prvý argument je regulárny výraz a druhý argument je vstupný text, ktorý sa porovná s regulárnym výrazom.

Možno budete chcieť určiť nový riadok (\ n) znak ako súčasť vstupného textu. Jediným spôsobom, ako to dosiahnuť, je určiť a \ znak nasledovaný znakom n znak. hlavný() prevádza túto postupnosť znakov na hodnotu Unicode 10.

Prevažná časť RegexDemoKód sa nachádza v skús-chytiť konštrukt. The skús blok najskôr odošle zadaný regulárny výraz a vstupný text a potom vytvorí a Vzor objekt, ktorý uchováva skompilovaný regulárny výraz. (Regexy sú kompilované, aby zlepšili výkon pri porovnávaní vzorov.) Z vyhľadávača je extrahovaný porovnávač Vzor objekt a používa sa na opakované hľadanie zhôd, kým žiadne nezostanú. The chytiť blok vyvoláva rôzne PatternSyntaxException metódy na získanie užitočných informácií o výnimke. Tieto informácie sa následne odosielajú.

V tomto okamihu nemusíte vedieť viac o fungovaní zdrojového kódu; to bude jasné, keď preskúmate API v časti 2. Je však potrebné zostaviť zoznam 1. Chyťte kód z výpisu 1 a potom zadajte nasledujúci príkazový riadok, ktorý chcete skompilovať RegexDemo:

javac RegexDemo.java

Vzor a jeho konštrukty

Vzor, prvá z troch tried obsahujúcich API Regex, je kompilovaná reprezentácia regulárneho výrazu. VzorDokumentácia SDK popisuje rôzne konštrukcie regexu, ale pokiaľ už nie ste náruživým používateľom regexu, môžu vás niektoré časti dokumentácie zmiasť. Čo sú kvantifikátory a aký je medzi tým rozdiel chamtivý, neochotnýa majetnícky kvantifikátory? Čo sú triedy znakov, hraničné zhody, spätné referenciea vložené príznakové výrazy? Na tieto a ďalšie otázky odpoviem v ďalších častiach.

Doslovné struny

Najjednoduchšou regexovou konštrukciou je doslovný reťazec. Niektorá časť vstupného textu sa musí zhodovať so vzorom tohto konštruktu, aby bola úspešná zhoda so vzorom. Uvažujme o nasledujúcom príklade:

java applet RegexDemo pre jablko

Tento príklad sa pokúša zistiť, či existuje zhoda s parametrom jablko vzor v applet vstupný text. Nasledujúci výstup odhalí zhodu:

regex = apple input = applet Nájdené [apple] začínajúce na 0 a končiace 4

Výstup nám ukazuje regulárny výraz a vstupný text, potom označuje úspešnú zhodu s jablko v rámci applet. Ďalej predstavuje počiatočný a konečný index príslušnej zhody: 0 a 4, resp. Počiatočný index identifikuje prvé umiestnenie textu, kde sa vyskytuje zhoda vzoru; koncový index identifikuje posledné umiestnenie textu pre zhodu.

Teraz predpokladajme, že zadáme nasledujúci príkazový riadok:

java RegexDemo jablkový krab

Tentokrát získame nasledujúcu zhodu s rôznymi počiatočnými a koncovými indexmi:

regex = apple input = crabapple Nájdené [apple] začínajúce na 4 a končiace na 8

Opačný scenár, v ktorom applet je regulárny výraz a jablko je vstupný text, neodhaľuje žiadnu zhodu. Celý regex sa musí zhodovať a v takom prípade vstupný text neobsahuje a t po jablko.

Metaznaky

Výkonnejšie konštrukcie regulárneho výrazu kombinujú doslovné znaky s metaznakmi. Napríklad v a.b, dobová metaznak (.) predstavuje akýkoľvek znak, ktorý sa objaví medzi a a b. Uvažujme o nasledujúcom príklade:

java RegexDemo .ox "Rýchla hnedá líška skáče cez lenivého vola."

Tento príklad špecifikuje .vôl ako regex a Rýchla hnedá líška preskočí lenivého vola. ako vstupný text. RegexDemo vyhľadáva v texte zhody, ktoré sa začínajú ľubovoľným znakom a končia sa vôl. Produkuje nasledujúci výstup:

regex = .ox input = Rýchla hnedá líška skáče cez lenivého vola. Nájdené [líška] začínajúca na 16 a končiace na 18 Nájdené [vôl] začínajúce na 39 a končiace o 41

Výstup odhaľuje dve zhody: líška a vôl (s vedúcim znakom medzery). The . metaznak zodpovedá f v prvom zápase a znak medzery v druhom zápase.

Čo sa stane, keď vymeníme .vôl s dobovým metaznakom? To znamená, aký výstup vyplynie zo zadania nasledujúceho príkazového riadku:

java RegexDemo. „Rýchla hnedá líška preskočí lenivého vola.“

Pretože metaznak sa zhoduje s akýmkoľvek znakom, RegexDemo vypíše zhodu pre každý znak (vrátane znaku ukončovacieho obdobia) vo vstupnom texte:

regulárny výraz =. input = Rýchla hnedá líška preskočí lenivého vola. Nájdené [T] začínajúce na 0 a končiace na 0 Nájdené [h] začínajúce na 1 a končiace na 1 Nájdené [e] začínajúce na 2 a končiace na 2 Nájdené [] začínajúce na 3 a končiace o 3 Nájdené [q] začínajúce na 4 a končiace 4 Nájdené [u] začínajúce na 5 a končiace 5 Nájdené [i] začínajúce 6 a končiace 6 Nájdené [c] začínajúce 7 a končiace 7 Nájdené [k] začínajúce 8 a končiace 8 Nájdené [ ] začínajúci na 9 a končiaci na 9 Nájdené [b] začínajúce na 10 a končiace na 10 Nájdené [r] začínajúce na 11 a končiace na 11 Nájdené [o] začínajúce na 12 a končiace o 12 Nájdené [w] začínajúce na 13 a končiace o 13 Nájdené [n] začínajúce na 14 a končiace o 14 Nájdené [] začínajúce na 15 a končiace o 15 Nájdené [f] začínajúce na 16 a končiace o 16 Nájdené [o] začínajúce na 17 a končiace o 17 Nájdené [x] začínajúce v 18 a končí v 18 Nájdené [] začínajúce na 19 a končiace o 19 Nájdené [j] začínajúce na 20 a končiace o 20 Nájdené [u] začínajúce na 21 a končiace o 21 Nájdené [m] začínajúce na 22 a končiace o 22 Nájdené [p] začínajúce na 23 a končiace o 23 Nájdené [s] st arting na 24 a končiace na 24 Nájdené [] začínajúce na 25 a končiace na 25 Nájdené [o] začínajúce na 26 a končiace o 26 Nájdené [v] začínajúce na 27 a končiace o 27 Nájdené [e] začínajúce na 28 a končiace na 28 Nájdené [r] začínajúce na 29 a končiace na 29 Nájdené [] začínajúce na 30 a končiace o 30 Nájdené [t] začínajúce na 31 a končiace o 31 Nájdené [h] začínajúce na 32 a končiace o 32 Nájdené [e] začínajúce na 33 a končiace na 33 Nájdené [] začínajúce na 34 a končiace 34 Nájdené [l] začínajúce na 35 a končiace 35 Nájdené [a] začínajúce na 36 a končiace 36 Nájdené [z] začínajúce na 37 a končiace 37 Nájdené [y ] začínajúci na 38 a končiaci na 38 nájdené [] začínajúce na 39 a končiace na 39 nájdené [o] začínajúce na 40 a končiace na 40 nájdené [x] začínajúce na 41 a končiace 41 nájdené [.] začínajúce na 42 a končiace o 42

Citovanie metaznakov

Špecifikovať . alebo ľubovoľný metaznak ako doslovný znak v regex konštrukcii, uveďte metaznak jedným z nasledujúcich spôsobov:

  • Pred metaznakom použite znak spätnej lomky.
  • Vložte metaznak medzi \ Q a \ E (napr. \ Q. \ E).

Nezabudnite zdvojnásobiť každý znak spätného lomítka (ako v \\. alebo \ Q. \ E), ktorý sa nachádza v reťazcovom doslovnom tvare, ako napr Reťazec regex = "\.";. Nezdvojujte znak spätného lomítka, keď sa zobrazuje ako súčasť argumentu príkazového riadku.

Triedy znakov

Niekedy musíme obmedziť znaky, ktoré budú vytvárať zhody s konkrétnou znakovou sadou. Mohli by sme napríklad vyhľadávať v texte samohlásky a, e, i, oa u, kde akýkoľvek výskyt samohlásky naznačuje zhodu. A trieda znakov identifikuje množinu znakov medzi metaznakmi hranatej zátvorky ([ ]), ktorý nám pomáha splniť túto úlohu. Vzor podporuje triedy znakov jednoduché, negácia, rozsah, zjednotenie, pretínanie a odčítanie. Na všetky tieto sa pozrieme nižšie.

Jednoduchá trieda znakov

The jednoduchá trieda znakov sa skladá zo znakov umiestnených vedľa seba a zhoduje sa iba s týmito znakmi. Napríklad, [abc] zodpovedá znakom a, ba c.

Uvažujme o nasledujúcom príklade:

java jaskyňa RegexDemo [csw]

Tento príklad sa iba zhoduje c so svojim náprotivkom v jaskyňa, ako je uvedené v nasledujúcom výstupe:

regex = [csw] input = jaskyňa Nájdené [c] začínajúce na 0 a končiace na 0

Trieda negatívnych znakov

The trieda znakov negácie začína na ^ metaznak a zhoduje sa iba s tými znakmi, ktoré sa nenachádzajú v tejto triede. Napríklad, [^ abc] zodpovedá všetkým znakom okrem a, ba c.

Zvážte tento príklad:

java jaskyňa RegexDemo "[^ csw]"

Upozorňujeme, že úvodzovky sú potrebné na mojej platforme Windows, ktorej shell zaobchádza s ^ postava ako úniková postava.

Tento príklad sa zhoduje a, va e s ich náprotivkami v jaskyňa, ako je zobrazené tu:

regex = [^ csw] input = jaskyňa Nájdené [a] začínajúce na 1 a končiace o 1 Nájdené [v] začínajúce na 2 a končiace o 2 Nájdené [e] začínajúce na 3 a končiace o 3

Trieda znakov rozsahu

The trieda znakov rozsahu sa skladá z dvoch znakov oddelených metaznakom spojovníka (-). Do rozsahu patria všetky znaky začínajúce znakom vľavo od pomlčky a končiace znakom vpravo od pomlčky. Napríklad, [a-z] sa zhoduje so všetkými malými abecednými znakmi. Je to ekvivalent špecifikácie [abcdefghijklmnopqrstuvwxyz].

Uvažujme o nasledujúcom príklade:

java RegexDemo [a-c] klaun

Tento príklad sa iba zhoduje c so svojim náprotivkom v klaun, ako je znázornené:

regex = [a-c] vstup = klaun Nájdené [c] začínajúce na 0 a končiace na 0

Zlúčenie viacerých rozsahov

Viaceré rozsahy môžete zlúčiť do jednej triedy znakov rozsahu tak, že ich umiestnite vedľa seba. Napríklad, [a-zA-Z] zhoduje sa so všetkými malými a veľkými abecednými znakmi.

Trieda znakov Únie

The trieda znakových odborov pozostáva z viacerých vnorených tried znakov a zhoduje sa so všetkými znakmi, ktoré patria do výsledného spojenia. Napríklad, [a-d [m-p]] zodpovedá znakom a cez d a m cez p.

Uvažujme o nasledujúcom príklade:

java RegexDemo [ab [c-e]] abcdef

Tento príklad sa zhoduje a, b, c, da e s ich náprotivkami v A b c d e f:

regex = [ab [ce]] input = abcdef Nájdené [a] začínajúce na 0 a končiace 0 nájdené [b] začínajúce na 1 a končiace 1 nájdené [c] začínajúce na 2 a končiace 2 nájdené [d] začínajúce na 3 a končí sa na 3 Nájdené [e] začínajúce na 4 a končiace na 4

Trieda znakov križovatky

The trieda znakov križovatky sa skladá zo znakov spoločných pre všetky vnorené triedy a zhoduje sa iba so spoločnými znakmi. Napríklad, [a-z && [d-f]] zodpovedá znakom d, ea f.

Uvažujme o nasledujúcom príklade:

java RegexDemo „[aeiouy && [y]]“ strana

Upozorňujeme, že úvodzovky sú potrebné na mojej platforme Windows, ktorej shell zaobchádza s & znak ako oddeľovač príkazov.

Tento príklad sa iba zhoduje r so svojim náprotivkom v večierok:

regex = [aeiouy && [y]] input = strana Nájdená [y] začínajúca na 4 a končiaca o 4
$config[zx-auto] not found$config[zx-overlay] not found