Performance
Certi elementi utilizzati per i criteri di riconoscimento sono più
efficienti di altri. E' più efficiente usare le classi di caratteri come
[aeiou] piuttosto che un gruppo di alternative come (a|e|i|o|u).
In generale la costruzione più semplice per ottenere un dato
scopo è la più efficiente. Nel libro di Jeffrey Friedl sono
illustrate varie tecniche sull'ottimizzazione delle espressioni
regolari.
Quando un criterio comincia con .* ed è attiva l'opzione PCRE_DOTALL, il
criterio è implicitamente ancorato da PCRE, dato che può riconoscere
solo l'inizio della stringa. Tuttavia, se non è attivo
PCRE_DOTALL,
PCRE non può fare questa ottimizzazione, perché il meta-carattere .
non riconosce più il carattere di "a capo", e quindi se la stringa
contiene dei caratteri di "a capo", il riconoscimento può par-
tire dal carattere immediatamente successivo ad uno di questi
e non dall'inizio. Ad esempio il criterio
(.*) second
può eseguire un riconoscimento nel testo "first\nand second"
(dove \n indica il carattere "a capo") ottenendo "and" come
prima stringa catturata. perché ciò accada è necessario che
PCRE possa iniziare il riconoscimento dopo ogni "a capo".
Se si deve usare un simile criterio in stringhe che non contengono
caratteri di "a capo", le performance migliori si possono
ottenere abilitando PCRE_DOTALL,
oppure iniziando il criterio con ^.* in modo da richiedere un
ancoraggio esplicito. Così si risparmia a PCRE di scandirsi il
testo alla ricerca di un "a capo" da cui ripartire per la ricerca.
Occorre prestare attenzione ai criteri che contengono ripetizioni
indefinite annidate. Possono richiedere molto tempo se
applicati a stringhe non riconoscibili. Si consideri il frammento
(a+)*
Questo può riconoscere "aaaa" in 33 modi differenti, e questo
numero può crescere molto rapidamente se la stringa da riconoscere è più lunga. (Il carattere
di ripetizione * può eseguire riconoscimenti per 0,1,2,3 o 4 ripetizioni, e per ciascuna di
esse, tranne lo 0, il carattere di ripetizione + può eseguire riconoscimenti per diversi
numeri di volte). Quindi se la parte successiva del criterio è tale
da non permettere il completamento del riconoscimento, PCRE, per principio,
ugualmente tenta tutte le possibili variazioni, richiedendo
diverso tempo.
Una ottimizzazione riesce a catturare qualche caso semplice
come in
(a+)*b
dove si indica che seguirà un carattere alfanumerico. PCRE,
prima di imbarcarsi nella procedura standard di riconoscimento,
verifica se nel testo vi è la lettera "b", e se non c'è
restituisce immediatamente un esito negativo. Tuttavia se non
viene indicata una lettera seguente questa ottimizzazione non
può essere utilizzata. Se ne può notare la differenza analizzando il comportamento del criterio
(a+)*\d
rispetto al precedente. Il primo, utilizzato con una stringa
composta da "a", fallisce immediatamente, l'ultimo richiede un
tempo apprezzabile, soprattutto se applicato a stringhe con
più di 20 caratteri.
arthur200126 at gmail dot com ¶10 months ago
> Beware of patterns that contain nested indefinite repeats. These can take a long time to run when applied to a string that does not match.
To say that it takes a "long time" is an understatement: the time taken would be exponential, specifically 2^n, where n is the number of "a" characters. This behavior could lead to a "regular expression denial of service" (ReDoS) if you run such a expression on user-provided input.
To not be hit by ReDoS, do one (or maybe more than one) of the three things:
* Write your expression so that it is not vulnerable. https://www.regular-expressions.info/redos.html is a good resource (both the "atomic" and "possessive" options are available in PHP/PCRE). Use a "ReDoS detector" or "regex linter" if your eyeballs can't catch all the issues.
* Set up some limits for preg_match. Use `ini_set(...)` on the values mentioned on https://www.php.net/manual/en/pcre.configuration.php. Reducing the limits might cause regexes to fail, but that is usually better than stalling your whole server.
* Use a different regex implementation. There used to be an RE2 extension; not any more!