Conosci i tuoi sapori regex
C'è una quantità sorprendente di persone che pensano che le espressioni regolari siano essenzialmente agnostiche del linguaggio. Tuttavia, in realtà ci sono differenze abbastanza sostanziali tra i sapori, e soprattutto per il golf del codice è bene conoscerne alcuni e le loro caratteristiche interessanti, in modo da poter scegliere il meglio per ogni attività. Ecco una panoramica di diversi sapori importanti e ciò che li distingue dagli altri. (Questo elenco non può davvero essere completo, ma fammi sapere se mi sono perso qualcosa di veramente evidente.)
Perl e PCRE
Li sto lanciando in un singolo piatto, poiché non ho troppa familiarità con il sapore Perl e sono per lo più equivalenti (dopotutto PCRE è per le espressioni regolari compatibili con Perl). Il vantaggio principale del sapore Perl è che puoi effettivamente chiamare il codice Perl dall'interno della regex e della sostituzione.
- Ricorsione / subroutine . Probabilmente la caratteristica più importante per il golf (che esiste solo in un paio di gusti).
- Modelli condizionali
(?(group)yes|no)
.
- Sostiene il cambiamento del caso nella stringa di sostituzione con
\l
, \u
, \L
e \U
.
- PCRE consente l'alternanza in lookbehinds, dove ogni alternativa può avere una lunghezza diversa (ma fissa). (La maggior parte dei gusti, incluso il Perl, richiede che i lookbehind abbiano una lunghezza fissa complessiva.)
\G
per ancorare una partita alla fine della partita precedente.
\K
per resettare l'inizio della partita
- PCRE supporta sia le proprietà dei caratteri Unicode che gli script .
\Q...\E
per sfuggire a serie più lunghe di personaggi. Utile quando stai cercando di abbinare una stringa che contiene molti meta-caratteri.
.NETTO
Questo è probabilmente il sapore più potente, con solo poche carenze.
Una lacuna importante in termini di golf è che non supporta quantificatori possessivi come altri sapori. Invece di .?+
dover scrivere (?>.?)
.
Giava
- A causa di un bug (vedi Appendice) Java supporta un tipo limitato di lookbehind di lunghezza variabile: puoi guardare indietro fino all'inizio della stringa con
.*
da dove puoi ora avviare un lookahead, come (?<=(?=lookahead).*)
.
- Supporta l'unione e l'intersezione delle classi di caratteri.
- Ha il supporto più esteso per Unicode, con classi di caratteri per "Script Unicode, blocchi, categorie e proprietà binarie" .
\Q...\E
come in Perl / PCRE.
Rubino
Nelle versioni recenti, questo sapore è altrettanto potente di PCRE, incluso il supporto per le chiamate di subroutine. Come Java, supporta anche l'unione e l'intersezione delle classi di caratteri. Una caratteristica speciale è la classe di caratteri integrata per le cifre esadecimali: \h
(e negata \H
).
La caratteristica più utile per giocare a golf è come Ruby gestisce i quantificatori. In particolare, è possibile nidificare i quantificatori senza parentesi. .{5,7}+
funziona e così fa .{3}?
. Inoltre, a differenza della maggior parte degli altri sapori, se il limite inferiore di un quantificatore è 0
che può essere omesso, ad esempio .{,5}
è equivalente a .{0,5}
.
Per quanto riguarda le subroutine, la principale differenza tra le subroutine PCRE e le subroutine di Ruby è che la sintassi di Ruby è un byte più lunga (?n)
rispetto a \g<n>
, ma le subroutine di Ruby possono essere utilizzate per l'acquisizione, mentre PCRE ripristina le acquisizioni al termine di una subroutine.
Infine, Ruby ha una semantica diversa per i modificatori relativi alla linea rispetto alla maggior parte degli altri sapori. Il modificatore che di solito viene chiamato m
in altri gusti è sempre attivo in Ruby. Quindi ^
e $
abbina sempre l'inizio e la fine di una riga, non solo l'inizio e la fine della stringa. Questo può farti risparmiare un byte se hai bisogno di questo comportamento, ma ti costerà byte extra se non lo fai, perché dovrai sostituire ^
e $
con \A
e \z
, rispettivamente. In aggiunta a ciò, il modificatore che di solito viene chiamato s
(che fa .
corrispondere gli avanzamenti di riga) viene invece chiamato m
in Ruby. Ciò non influisce sul conteggio dei byte, ma deve essere tenuto presente per evitare confusione.
Pitone
Python ha un sapore solido, ma non sono a conoscenza di funzioni particolarmente utili che non troverai da nessun'altra parte.
Tuttavia , esiste un sapore alternativo che è destinato a sostituire il re
modulo ad un certo punto e che contiene molte caratteristiche interessanti. Oltre ad aggiungere il supporto per la ricorsione, i lookbehinds di lunghezza variabile e gli operatori di combinazione di classi di caratteri, ha anche la caratteristica unica della corrispondenza fuzzy . In sostanza è possibile specificare un numero di errori (inserimenti, eliminazioni, sostituzioni) consentiti e il motore fornirà anche corrispondenze approssimative.
ECMAScript
Il sapore di ECMAScript è molto limitato e quindi raramente molto utile per giocare a golf. L'unica cosa che sta succedendo è che la classe di caratteri vuota negata si [^]
abbina a qualsiasi personaggio così come la classe di caratteri vuota che fallisce incondizionatamente []
(al contrario del solito (?!)
). Sfortunatamente, il sapore non ha alcuna caratteristica che lo rende utile per i normali problemi.
Lua
Lua ha il suo sapore abbastanza unico, che è piuttosto limitato (ad esempio non puoi nemmeno quantificare i gruppi) ma presenta una manciata di funzioni utili e interessanti.
- Ha un gran numero di abbreviazioni per le classi di caratteri integrate , tra cui punteggiatura, caratteri maiuscoli / minuscoli e cifre esadecimali.
- Con
%b
esso supporta una sintassi molto compatta per abbinare stringhe bilanciate. Ad esempio %b()
abbina a (
e quindi tutto fino a un abbinamento )
(saltando correttamente coppie accoppiate interne). (
e )
può contenere due caratteri qui.
Incremento
Il sapore regex di Boost è essenzialmente quello di Perl. Tuttavia, ha alcune nuove e interessanti funzionalità per la sostituzione di regex, tra cui cambiamenti di caso e condizioni . Quest'ultimo è unico per Boost per quanto ne so.