0xDEADBEEF

RSS
««« »»»

Java, Scala a regulární výrazy

26. 11. 2017

Poslední dobou zjišťuji, že práce s regulárními výrazy v Javě a Scale je neuspokojivá, matoucí a API nikdy nenabízí přesně to, co bych chtěl.

Scala má krásně vypadající metodu Regex#replaceAllIn(String, Match => String). Na první pohled je všechno jasné: Každý výskyt regulárního výrazu v prvním argumentu je předán funkci Match => String. Objekt typu Match reprezentuje výskyt vzoru. Funkce ho vezme jako argument a vyprodukuje string, který ho nahradí. Co by na tom mohlo být komplikovaného, žeano?

Jednoduché volání, které na první pohled vypadá jako identita, není bezpečné:

regex.replaceAllIn(str, (m: Match) => m.group(0))

m.group(0) představuje celou shodu (ostatní indexy jsou uzávorkované výrazy v regexu, m.group(1) jsou první závorky, m.group("named") jsou závorky pojmenované named) .

V čem je problém?

V tom, že výsledek funkce se nepoužije verbatim pro nahrazení, ale je interpretován. Každý výskyt řetězců $0 - $9 je interpretován jako podvýraz a \$ znamená literál $. Když vstupní data obsahují dolar následovaný číslem, skončí to přinejlepším výjimkou, přinejhorším to udělá něco nečekaného. A to není to, co by člověk čekal nebo chtěl. V dokumentaci je toto chování dobře popsané, ale nepůsobí to, že by to tak mělo být.

Korektní verze by měla vypadat takhle:

regex.replaceAllIn(str, (m: Match) => Regex.quoteReplacement(m.group(0)))

Interpretace stringu je přežitek starších API, které nenabízely nahrazení přes fukci:

regex.replaceAllIn(str, replace: String)

V tomto případě nemůžu specifikovat logiku, která vypočítá nahrazovací string a proto jsou použity zpětné reference jako $0 - $9. Ty poskytují aspoň nějakou rudimentární flexibilitu.

Problém je v tom, že výsledný string musí být escapován a hned potom je interpretován (pro $\$), což je zbytečná práce, která stojí zbytečný čas.1

Ocenil bych jasné API s metodami jako

které jasně říkají, co dělají a uživatel si může vybrat přesně to chování, které potřebuje.


  1. Dodatek: I když má quoteReplacement měřitelnou režii, je téměř zanedbatelná. Implementace počítá s tím, že v naprosté většině případů nebude třeba nic escapovat.
píše k47 (@kaja47, k47)