Programování

Regulární výrazy v Javě, část 1: Porovnávání vzorů a třída Pattern

Třídy znaků a rozmanitých řetězců Java nabízejí nízkou úroveň podpory pro porovnávání vzorů, ale tato podpora obvykle vede ke složitému kódu. Pro jednodušší a efektivnější kódování nabízí Java Regex API. Tento dvoudílný kurz vám pomůže začít s regulárními výrazy a Regex API. Nejprve rozbalíme tři mocné třídy sídlící v java.util.regex balíček, pak prozkoumáme Vzor třída a její propracované konstrukce odpovídající vzorům.

stáhnout Získat kód Stáhněte si zdrojový kód například pro aplikace v tomto výukovém programu. Vytvořil Jeff Friesen pro JavaWorld.

Co jsou regulární výrazy?

A regulární výraz, také známý jako a regulární výraz nebo regulární výraz, je řetězec, jehož vzor (template) popisuje sadu řetězců. Vzor určuje, které řetězce patří do sady. Vzor se skládá z doslovných znaků a metaznaky, což jsou znaky, které mají zvláštní význam místo doslovného významu.

Shoda vzoru je proces hledání textu k identifikaci zápasy, nebo řetězce, které odpovídají vzoru regulárního výrazu. Java podporuje porovnávání vzorů prostřednictvím svého Regex API. API se skládá ze tří tříd -Vzor, Matcher, a PatternSyntaxException--všechny se nacházejí v java.util.regex balík:

  • Vzor objekty, známé také jako vzory, jsou kompilované regulární výrazy.
  • Matcher předměty nebo dohazovači, jsou motory, které interpretují vzory k vyhledání shody sekvence znaků (objekty, jejichž třídy implementují java.lang.CharSequence rozhraní a sloužit jako textové zdroje).
  • PatternSyntaxException objekty popisují nelegální vzory regulárních výrazů.

Java také poskytuje podporu pro porovnávání vzorů různými způsoby řetězec java.lang třída. Například, booleovské zápasy (String regex) vrací true jen když vyvolávající řetězec přesně odpovídá regulární výrazje regulární výraz.

Pohodlné metody

V zákulisí, zápasy() a TětivaDalší metody pohodlí orientované na regex jsou implementovány v podmínkách Regex API.

RegexDemo

Vytvořil jsem RegexDemo aplikace pro demonstraci regulárních výrazů Java a různých metod umístěných v Vzor, Matcher, a PatternSyntaxException třídy. Zde je zdrojový kód ukázky:

Výpis 1. Demonstrace regexů

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 ("usage: java RegexDemo regex input"); vrátit se; } // Převést posloupnosti znaků nového řádku (\ n) na znaky nového řádku. 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 ("Nalezeno [" + m.group () + "] začínající na" + m.start () + "a končící na" + (m.end () - 1)); } catch (PatternSyntaxException pse) {System.err.println ("Bad regex:" + pse.getMessage ()); System.err.println ("Popis:" + pse.getDescription ()); System.err.println ("Index:" + pse.getIndex ()); System.err.println ("Nesprávný vzor:" + pse.getPattern ()); }}}

První věc RegexDemoje hlavní() metoda dělá, je ověřit jeho příkazový řádek. To vyžaduje dva argumenty: první argument je regex a druhý argument je vstupní text, který má být porovnán s regexem.

Možná budete chtít zadat nový řádek (\ n) znak jako součást vstupního textu. Jediným způsobem, jak toho dosáhnout, je zadat a \ znak následovaný znakem n charakter. hlavní() převede tuto posloupnost znaků na hodnotu Unicode 10.

Převážná část RegexDemoKód je umístěn v Snaž se-chytit postavit. The Snaž se block first output the specified regex and input text and then creates a Vzor objekt, který ukládá kompilovaný regulární výraz. (Regexy se kompilují, aby se zlepšil výkon při porovnávání vzorů.) Z nástroje je extrahován porovnávač Vzor objekt a slouží k opakovanému hledání shod, dokud žádný nezůstane. The chytit blok vyvolává různé PatternSyntaxException metody k získání užitečných informací o výjimce. Tato informace se následně odešle.

V tuto chvíli nepotřebujete vědět více o fungování zdrojového kódu; to bude jasné, když prozkoumáte API v Části 2. Je však nutné sestavit Výpis 1. Chyťte kód z výpisu 1 a poté do příkazového řádku zadejte následující příkaz ke kompilaci RegexDemo:

javac RegexDemo.java

Vzor a jeho konstrukce

Vzor, první ze tří tříd zahrnujících Regex API, je kompilovaná reprezentace regulárního výrazu. VzorDokumentace SDK popisuje různé konstrukce regulárního výrazu, ale pokud již nejste zaníceným uživatelem regulárního výrazu, mohou vás části dokumentace zmást. Jaké jsou kvantifikátory a jaký je mezi nimi rozdíl chamtivý, neochotný, a Přivlastňovací kvantifikátory? Jaké jsou třídy postav, hraniční srovnávače, zpětné odkazy, a vložené výrazy příznaků? Na tyto a další otázky odpovím v následujících částech.

Doslovné řetězce

Nejjednodušší regex konstrukce je doslovný řetězec. Některá část vstupního textu musí odpovídat vzoru tohoto konstruktu, aby byla úspěšná shoda vzoru. Zvažte následující příklad:

java RegexDemo Apple applet

Tento příklad se pokusí zjistit, zda existuje shoda pro jablko vzor v applet vstupní text. Následující výstup odhalí shodu:

regex = apple input = applet Nalezeno [apple] od 0 do 4

Výstup nám ukazuje regex a vstupní text, poté označuje úspěšnou shodu jablko v rámci applet. Dále představuje počáteční a koncový index dané shody: 0 a 4, resp. Počáteční index identifikuje první textové umístění, kde se vyskytuje shoda vzoru; koncový index identifikuje poslední umístění textu pro shodu.

Nyní předpokládejme, že zadáme následující příkazový řádek:

java RegexDemo jablečný krabík

Tentokrát získáme následující shodu s různými počátečními a koncovými indexy:

regex = apple input = crabapple Nalezeno [apple] začínající na 4 a končící v 8

Opačný scénář, ve kterém applet je regulární výraz a jablko je vstupní text, neodhalí žádnou shodu. Celý regulární výraz musí odpovídat a v tomto případě vstupní text neobsahuje a t po jablko.

Metaznaky

Výkonnější konstrukce regulárního výrazu kombinují doslovné znaky s metaznaky. Například v a. b, dobová metaznak (.) představuje libovolný znak, který se objeví mezi A a b. Zvažte následující příklad:

java RegexDemo .ox "Rychlá hnědá liška skáče přes líného vola."

Tento příklad určuje .vůl jako regex a Rychlá hnědá liška skáče přes líného vola. jako vstupní text. RegexDemo vyhledá v textu shody, které začínají libovolným znakem a končí vůl. Produkuje následující výstup:

regex = .ox input = Rychlá hnědá liška skáče přes líného vola. Nalezeno [liška] začínající na 16 a končící na 18 Nalezeno [vůle] začínající na 39 a končící na 41

Výstup odhaluje dvě shody: liška a vůl (s vedoucím znakem mezery). The . metaznak odpovídá F v první shodě a znak mezery ve druhé shodě.

Co se stane, když vyměníme .vůl s dobovým metaznakem? To znamená, jaký výstup je výsledkem zadání následujícího příkazového řádku:

java RegexDemo. „Rychlá hnědá liška skáče přes líného vola.“

Protože metaznak období odpovídá jakémukoli znaku, RegexDemo vypíše shodu pro každý znak (včetně znaku ukončovacího období) ve vstupním textu:

regulární výraz =. input = Rychlá hnědá liška skáče přes líného vola. Nalezeno [T] začínající na 0 a končící na 0 Nalezené [h] začínající na 1 a končící na 1 Nalezené [e] začínající na 2 a končící na 2 Nalezené [] začínající na 3 a končící na 3 Nalezené [q] začínající na 4 a končící na 4 Nalezeno [u] začínající na 5 a končící na 5 Nalezené [i] začínající na 6 a končící na 6 Nalezeno [c] začínající na 7 a končící na 7 Nalezeno [k] začínající na 8 a končící na 8 Nalezeno [ ] začínající na 9 a končící na 9 nalezené [b] začínající na 10 a končící na 10 nalezené [r] začínající na 11 a končící na 11 nalezené [o] začínající na 12 a končící na 12 nalezené [w] začínající na 13 a končící ve 13 Nalezeno [n] počínaje 14 a končící ve 14 Nalezeno [] počínaje 15 a končící v 15 Nalezeno [f] počínaje 16 a končící v 16 Nalezeno [o] počínaje 17 a končící 17 Nalezeno [x] počínaje v 18 a končí v 18 Nalezeno [] začíná v 19 a končí v 19 Nalezeno [j] začíná v 20 a končí v 20 Nalezeno [u] začíná v 21 a končí v 21 Nalezeno [m] začíná v 22 a končí v 22 Nalezeno [p] začínající na 23 a končící na 23 Nalezeno [s] sv arting ve 24 a končící ve 24 Nalezeno [] začínající na 25 a končící na 25 Nalezené [o] začínající na 26 a končící na 26 Nalezené [v] začínající na 27 a končící na 27 Nalezené [e] začínající na 28 a končící na 28 Nalezeno [r] začínající na 29 a končící na 29 Nalezené [] začínající na 30 a končící na 30 Nalezené [t] začínající na 31 a končící na 31 Nalezené [h] začínající na 32 a končící na 32 Nalezené [e] začínající na 33 a končící na 33 Nalezeno [] začínající na 34 a končící na 34 Nalezeno [l] začínající na 35 a končící na 35 Nalezeno [a] začínající na 36 a končící na 36 Nalezeno [z] začínající na 37 a končící na 37 Nalezeno [y ] začínající na 38 a končící na 38 nalezené [] začínající na 39 a končící na 39 nalezené [o] začínající na 40 a končící na 40 nalezené [x] začínající na 41 a končící na 41 nalezené [.] začínající na 42 a končící na 42

Cituji metaznaky

Specifikovat . nebo jakýkoli metaznak jako doslovný znak v konstrukci regulárního výrazu, citujte metaznak jedním z následujících způsobů:

  • Předcházejte metaznaku znakem zpětného lomítka.
  • Umístěte metaznak mezi \ Q a \E (např., \ Q. \ E).

Nezapomeňte zdvojnásobit každý znak zpětného lomítka (jako v \\. nebo \ Q. \ E), který se objeví v řetězcovém literálu, jako je Řetězec regex = "\.";. Nezdvojujte znak zpětného lomítka, pokud se objeví jako součást argumentu příkazového řádku.

Třídy znaků

Někdy musíme omezit znaky, které budou vytvářet shody s konkrétní znakovou sadou. Mohli bychom například hledat v textu samohlásky A, E, i, Ó, a u, kde jakýkoli výskyt samohlásky naznačuje shodu. A třída znaků identifikuje sadu znaků mezi metaznaky hranatých závorek ([ ]), což nám pomáhá splnit tento úkol. Vzor podporuje třídy znaků jednoduché, negace, rozsah, sjednocení, průnik a odčítání. Na všechny tyto se podíváme níže.

Jednoduchá třída znaků

The jednoduchá třída znaků skládá se ze znaků umístěných vedle sebe a odpovídá pouze těmto znakům. Například, [abc] odpovídá znakům A, b, a C.

Zvažte následující příklad:

java jeskyně RegexDemo [csw]

Tento příklad odpovídá pouze C s protějškem v jeskyně, jak je znázorněno v následujícím výstupu:

regex = [csw] input = jeskyně Nalezeno [c] začínající na 0 a končící na 0

Negativní třída znaků

The třída znaků negace začíná na ^ metaznak a odpovídá pouze těm znakům, které se nenacházejí v dané třídě. Například, [^ abc] odpovídá všem znakům kromě A, b, a C.

Zvažte tento příklad:

java jeskyně RegexDemo "[^ csw]"

Všimněte si, že uvozovky jsou nutné na mé platformě Windows, jejíž shell zachází s ^ postava jako úniková postava.

Tento příklad odpovídá A, proti, a E s jejich protějšky v jeskyně, jak je znázorněno zde:

regex = [^ csw] input = jeskyně Nalezeno [a] začínající na 1 a končící na 1 Nalezené [v] začínající na 2 a končící na 2 Nalezené [e] začínající na 3 a končící na 3

Třída znaků rozsahu

The třída znaků rozsahu skládá se ze dvou znaků oddělených metaznakem pomlčky (-). Všechny znaky začínající znakem nalevo od pomlčky a končícím znakem napravo od pomlčky patří do rozsahu. Například, [a-z] odpovídá všem malým abecedním znakům. Je to ekvivalent zadání [abcdefghijklmnopqrstuvwxyz].

Zvažte následující příklad:

java RegexDemo [a-c] klaun

Tento příklad odpovídá pouze C s protějškem v klaun, jak je znázorněno:

regex = [a-c] vstup = klaun Nalezeno [c] začínající na 0 a končící na 0

Sloučení více rozsahů

Můžete sloučit více rozsahů do stejné třídy znaků rozsahu jejich umístěním vedle sebe. Například, [a-zA-Z] odpovídá všem malým a velkým abecedním znakům.

Třída znaků Unie

The třída odborových znaků skládá se z několika vnořených tříd znaků a odpovídá všem znakům, které patří do výsledného sjednocení. Například, [a-d [m-p]] odpovídá znakům A přes d a m přes p.

Zvažte následující příklad:

java RegexDemo [ab [c-e]] abcdef

Tento příklad odpovídá A, b, C, d, a E s jejich protějšky v a B c d e f:

regex = [ab [ce]] input = abcdef Nalezeno [a] začínající na 0 a končící na 0 Nalezené [b] začínající na 1 a končící na 1 Nalezené [c] začínající na 2 a končící na 2 Nalezené [d] začínající na 3 a končící na 3 Nalezeno [e] počínaje 4 a končící 4

Třída křižovatek znaků

The třída znaků průniku skládá se ze znaků společných pro všechny vnořené třídy a odpovídá pouze společným znakům. Například, [a-z && [d-f]] odpovídá znakům d, E, a F.

Zvažte následující příklad:

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

Všimněte si, že uvozovky jsou nutné na mé platformě Windows, jejíž shell zachází s & znak jako oddělovač příkazů.

Tento příklad odpovídá pouze y s protějškem v strana:

regex = [aeiouy && [y]] input = party Nalezeno [y] počínaje 4 a končící 4