Sostituzioni e traslazioni


Oltre ad identificare le espressioni regolari Perl può anche effettuare delle sostituzioni basate sui 'matches'. Ciò si ottiene usando la funzione s che simula il modo in cui la sostituzione è fatta dall'editor di testo vi. Si può utilizzare l'operatore di match oppure, se è omesso si assume che la sostituzione avvenga sullla variabile speciale $_ (così come accade per il matching tra stringhe).

Per rimpiazzare una occorrenza di london con London nella stringa $sentence si può usare la seguente espressione

$sentence =~ s/london/London/
e per fare lo stesso con la variabile speciale $_ , possiamo scrivere
s/london/London/
Da notare che le due espressioni regolari (london and London) sono racchiuse tra / slashes. Il risultato di questa espressione è il numero di sostituzioni fatte, perciò può essere 0 (falso) oppure 1 (vero) in questo caso.


Opzioni

L' esempio mostrato rimpiazza solo la prima occorrenza della stringa, ma potrebbero esserci più stringhe da voler rimpazzare. Per ottenere una sostituzione globale l'ultimo slash deve essere seguito da una g:
s/london/London/g
lo stesso funziona anche se eseguito rispetto alla variabile speciale $_. Nuovamente, l'espressione restituisce il numero di sostituzioni effettuate, che può essere 0 (falso) o anche maggiore di zero (vero).

Se vogliamo anche rimpiazzare le occorrenz di lOndon, lonDON, LoNDoN e così via allora dovremmo usare

s/[Ll][Oo][Nn][Dd][Oo][Nn]/London/g
ma un modo più semplice di farlo è quello di usare l'opzione i ("ignore case"). L'espressione
s/london/London/gi
effettua una sostituzione globale, ignorando se si tratta di caratteri maiuscoli o minuscoli. L'opzione i è usata anche nel match di espressioni regolari /.../.


Tenere memoria dei Patterns

Spesso è utile potersi ricordare dei pattern per cui c'è stato un match, così da poterli nuovamente usare. Ciò che avviene è che qualsiasi stringa soddisfa un match è memorizzata nelle variabili $1,...,$9. Queste stringhe possono essere usate nelle espressisoni regolari o nelle sostituzioni mediante i codici speciali \1,...,\9. Per esempio:
$_ = "Lord Whopper of Fibbing";
s/([A-Z])/:\1:/g;
print "$_\n";
rimpiazzerà ogni lettera maiuscola con la stessa lettera racchiusa tra i due punti. Quindi stamperà :L:ord :W:hopper of :F:ibbing. Le variabili $1,...,$9 sono di sola lettura, perciò non possono essere modificate.

Come altro esempio, il test

if (/(\b.+\b) \1/)
{
	print "Found $1 repeated\n";
}
identificherà qualsiasi parola ripetuta. Ogni \b rappresenta un confine di una parola (word boundary) ed il + effettua un match su ogni stringa non vuota , perciò \b.+\b verifica un match per qualsiasi cosa tra i due confini di parola. Ciò che compare tra parentesi viene memorizzato mediante il codice \1 per le espressioni regolari e come $1 per il resto del programma.

Il seguente codice scambia il primo e l'ultimo carattere della linea nella variabile $_ :

s/^(.)(.*)(.)$/\3\2\1/

Il ^ e $ servono per trovare un match all'inizio e alla fine della linea. Il codice \1 memorizza il primo carattere; il codice \2 memorizza quello che segue e l'ultimo carattere è memorizzato nel codice \3. Allora l'intera linea è rimpiazzata scambiando di posto \1 e \3.

Dopo un match, è possibile anche usare una variabile speciale di sola lettura $` e $& e $' per cercare cosa ha soddisfatto il match prima, durante e dopo la ricerca. Perciò, per il match

$_ = "Lord Whopper of Fibbing";
/pp/;
tutte le seguenti espressioni risultano vere. (Ricordarsi che eq è il test di uguaglianza tra stringhe.)
$` eq "Lord Wo";
$& eq "pp";
$' eq "er of Fibbing";

Infine, è importante ricordare che ciò che compare tra / slashes di un match o di una sostituzione viene sempre interpretato. Perciò

$search = "the";
s/$search/xxx/g;
rimpiazzerà ogni occorrenza di the con xxx. Ad esempio, volendo rimpiazzare ogni occorrenza di there non sarebbe corretto scrivere s/$searchre/xxx/ perchè sarà interpretato come variabile $searchre. Al contrario si dovrebbe racchiudere il nome della variabile tra parentesi graffe così che il codice diventi
$search = "the";
s/${search}re/xxx/;


Traslazione

La funzione tr consente la traslazione carattere per carattere. La seguente espressione rimpiazza ogni a con e, ogni b con d, ed ogni c con f nella variabile $sentence. L'espressione restituisce il numero di sostituzioni effettuate.
$sentence =~ tr/abc/edf/

La maggior parte dei codici speciali RE non si applicano nella funzione tr. Per esempio, la sentenza di seguito conta il numero di asterischi nella varibile $sentence e li memorizza nella variabile $count.

$count = ($sentence =~ tr/*/*/);
Ancora, il - è usato per indicare "tra". Questa traslazione converte $_ in maiuscolo.
tr/a-z/A-Z/;


Esercizio

Il programma allo stato attuale dovrebbe contare il numero di linee del file che contiene determinate stringhe. Modificarlo in modo tale che conti le linee in cui compaiono lettere doppie (o altri caratteri doppi). Modificarlo nuovamente in modo che queste lettere doppie appaiano solo tra parentesi. Per esempio il programma dovrebbe produrre una linea come:
023 Amp, James Wa(tt), Bob Transformer, etc. These pion(ee)rs conducted many
Modificare il programma in modo tale che tutte le coppie di lettere compaiano tra parentesi, non solo la prima di ciascuna linea.

Supponendo che il programma si chiami countlines, è possibile eseguirlo nel seguente modo:

./countlines
Inoltre, se si prova ad invocare con diversi argomenti, come per esempio
./countlines first second etc
questi argomenti saranno memorizzati nell'array @ARGV. Nell'esempio di sopra si verifica che $ARGV[0] è first e $ARGV[1] è second e $ARGV[2] è etc. Modificare il programma in modo tale che accetti un argomento e conti solo le linee in cui compare la stringa passata come argomento. Dovrebbe anche mettere le occorrenze di questa stringa tra parentesi. Così,
./countlines the
darà in output qualcosa come:
019 But (the) greatest Electrical Pioneer of (the)m all was Thomas Edison, who