EDIT 10.12.2016: Projekt Re jsem již ukončil a smazal ze svého GitHubu, jelikož ho nyní plně nahradilo Rojo.

S nástupem Javy 8 se nám sice otevřely nové možnosti s lambda funkcemi, ale standardní třída pro regulární výrazy Pattern zůstala stejná. A tak jsem si řekl, že by bylo fajn, kdybychom v Javě mohli psát regulární výrazy se stejnou lehkostí, jako např. s pomocí modulu re v Pythonu. Na internetu jsem hledal podobné knihovny, které by již toto umožňovaly, ale nic se mi nepodařilo najít (čímž nevylučuji, že jsem hledal špatně 🙂 ). Pojďme se tedy na to podívat trochu blíže …

Co je knihovna Re a k čemu slouží

Je to vlastně takový malý wrapper nad již standardním Javovským regexovým enginem, který umožňuje provádět některé složitější regexové operace vcelku pohodlným způsobem s pomocí lambda funkcí. Pokud vás už nebaví psát pořád dokola Pattern.compile(…).match(…), anebo se vám nechce kvůli hledání jediného matche psát while() cyklus, pak tahle knihovna by vám mohla přijít vhod. Samotná třída Re() neobsahuje žádný vnitřní stav, a všechny její funkce jsou “pure”, takže je zcela thread-safe. Knihovnu si můžete stáhnout přímo z GitHubu projektu (Jar ve složce release).

Příklad použití

Nejdříve si vytvořím instanci:

Re re = new Re();

anebo pokud chci z nějakého důvodu šetřit paměť, tak zvolím singleton:

Re re = Re.instance();

Nyní řekněme, že chci najít podřetězec bcd (kde cd si dám navíc jako grupu) v řetězci abcde. K tomu slouží metoda search(), která vrací Matcher, anebo null, pokud nic nebylo nalezeno:

Matcher m = re.search("b(cd)", "abcde");
m.group(1); // "cd"

Pokud chci najít např. všechny trojice znaků a rovnou získat List<String>, pak použiju findAll():

List<String> results = re.findAll(".{3}", "abcdef"); // [abc, def]

Podobně chci-li provádět nějaké další transformace, kde potřebuji mít Matcher, tak k tomu mi poslouží metoda findIter(). S pomocí Javaslangu si pak vytvoříme list Stringů, kde všechny nalezené řetězce budou v upper case:

Iterable<Matcher> iterable = re.findIter(".{3}", "abcdef");
List<String> list = Stream.ofAll(iterable)
        .map(m -> m.group().toUpperCase())
        .toJavaList(); // [ABC, DEF]

a nakonec metoda sub(), která slouží pro komplikovanější substituce, kde opět potřebuji mít k dispozici Matcher a výsledkem je nahrazený String:

re.sub("b.", m -> m.group().toUpperCase(), "abcd"); // "aBCd"

Toť vše :-). Závěrem budu rád, když mi v komentářích zanecháte vaše názory/připomínky/náměty.