Expressions Regulars

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Introducció

Acabes de veure la utilitat de les expressions regulars en el fitxer de configuració d'un proxy com el Squid. Altres vegades també hem trobat expressions regulars i hi hem passat de puntetes. Les expressions regulars (regex) serveixen per a reconeixement i detecció de cadenes (matching) i s'utilitzen sovint, per exemple en scripts bash (un exemple típic pot ser formatar la data amb el format que un vol). El primer exemple que pots provar en la consola és:

line='Today is 10/12/2010 and yesterday was 9/11/2010'
echo "$line" | sed -r 's#([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})#\3-\2-\1#g'

Today is 2010-12-10 and yesterday was 2010-11-9

En aquest cas sed' és útil per transformar la cadena de text en una altra.

Teoria

Les expressions regulars (regex) estan formades per caràcters i metacaràcters. Els caràcters normals inclouen lletres (majúscules i minúscules) i números. Els metacaràcters tenen un significat especial, com es comenta més avall. En el cas més simple, una cadena com ara paper no conté metacaràcters, i coincideix amb paperot, 12paper45, però no amb PAPER.

Per veure la potència de les expressions regulars és molt important entrendre els metacaràcters:

Proves

Per començar a provar expressions regulars ho farem, per exemple, amb grep

GREP(1)                          User Commands                         GREP(1)

NAME
       grep, egrep, fgrep, rgrep - print lines matching a pattern

SYNOPSIS
       grep [OPTIONS] PATTERN [FILE...]
       grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]

DESCRIPTION
       grep  searches the named input FILEs (or standard input if no files are
       named, or if a single hyphen-minus (-) is given as file name) for lines
       containing  a  match to the given PATTERN.  By default, grep prints the
       matching lines.
...
REGULAR EXPRESSIONS

       A  regular  expression  is  a  pattern that describes a set of strings.
       Regular expressions are constructed analogously to  arithmetic  expres-
       sions, by using various operators to combine smaller expressions.
...

Les expressions regulars tenen algun comportament que depenen de l'eina amb què les avalues. Per tant, s'ha d'anar a la referència de l'eina (com ara grep, vi, awk, sed, perl,...) per tal de veure la compatibilitat (veure la taula de Regular Expressions Syntax Support a baix de tot de l'enllaç que se't proposa).

fitxer test.txt:

he is a rat
he is in a rut
the food is Rotten
I like root beer

El punt . (amb anglès period) representa qualsevol caràcter. Si volem trobar totes les línies que continguin r.t (una paraula de tres caràcters que comenci per r i acabi per t):

$ cat test.txt | grep r.t
he is a rat
he is in a rut

o bé

$ grep r.t test.txt
he is a rat
he is in a rut

Si volem que no sigui sensible a majúscules per a la r farem:

$ grep [Rr].t test.txt
he is a rat
he is in a rut
the food is Rotten

Per detectar una cadena al principi de la línia fem servir el ^ (circunflex o caret):

$ grep ^ĥe test.txt
he is a rat
he is in a rut

fixem-nos que no detecta the

L'ús del circumflex té un altre ús: quan utilitzem ^ com a primer caràcter dins dels brackets [] vol dir detectar qualsevol caràcter que no estigui en el rang. Per exemple, per detectar he però que no sigui the o she farem:

$ grep [^st]he test.txt

no troba el the (però tampoc troba he is a rat i he is in a rut perquè espera que hi hagi un caràcter abans del he).

[A-Za-z] detecta qualsevol lletra de l'alfabet, sigui majúscula o minúscula. L'expressió regular [A-Za-z][A-Za-z]* detecta una lletra seguida de 0 (cap) o més lletres.

$ grep [o]* test.txt -> mostra les coincidències de ''cap o alguna o''
 he is a rat
he is in a rut
the food is Rotten
I like root beer
$ grep [o][o]* test.txt -> mostra les coincidències de ''cap o alguna o, després d'una o''
the food is Rotten
I like root beer

Per especificar el número d'ocurrències que es detecten podem utilitzar les claus. Per exemple, per detectar les instàncies de 100 i 1000, però no 10 i 10000 farem: 10\{2,3\}.

$ echo 10 100 1000 10000 | grep "10\{2,3\}"

resultat: 10 100 1000 10000

Fixa't bé amb la diferència amb el següent cas:

$ echo 10 100 1000 10000 | grep "[10]\{2,3\}"

10 100 1000 10000

$ echo 10 100 1000 | grep "[[:digit:]]\{2,3\}"

resultat: 10 100 1000

Un exemple aclaridor: (\{i\} Match a specific number of instances or instances within a range of the preceding character)

$ echo 10000 | grep "[10]\{1\}" -> els números sempre es repeteixen ells mateixos

10000

$ echo 10000 | grep "[10]\{2\}" -> detecta l'expressió que és un número que al seu darrere hi ha un altre número (0 o 1)

10000

$ echo 10000 | grep "[10]\{3\}" -> detecta el número que es repeteix amb 1 o 0 tres vegades

10000

$ echo 10000 | grep "[10]\{4\}" -> detecta el número que es repeteix amb 1 o 0 quatre vegades

10000

$ echo 10000 | grep "[10]\{5\}" -> detecta el número que es repeteix amb 1 o 0 cinc vegades

10000

$ echo 10000 | grep "[10]\{6\}"

100000

Com pots comprovar, les Expressions Regulars poden ser un bon embolic... però realment són molt útils i s'utilitzen molt.

Corolari (el que potser utilitzaràs més)

Moltes vegades es planteja trobar dins d'una col.lecció de fitxers totes les vegades que surt una determinada paraula. Imagina't que comets habitualment l'error ortogràfic lampara (en comptes de làmpara). Imaginem que tenim dos fitxers dins una carpeta (però podrien ser 1000 fitxers amb una estructura de carpetes i subcarpetes).

Crea la carpeta lampara i fica-hi aquests dos fitxers:

fitxer1.txt

la lampara d'Aladí s'ha fos
no trobo la lampara del Pere

fitxer2.txt

he anat a la botiga
a comprar una lampara i una taula
$ find /home/joan/lampara/ -type f -print | xargs grep -i lampara | more
/home/joan/lampara/fitxer1.txt:la lampara d'Aladí s'ha fos
/home/joan/lampara/fitxer1.txt:no trobo la lampara del Pere
/home/joan/lampara/fitxer2.txt:a comprar una lampara i una taula

És una combinació de les comandes find, xargs i grep:

Així et serà fàcil subsanar tots els errors.

Hi ha alguna manera de reemplaçar totes les ocurrències? (que no sigui amb un editor gràfic tipus gedit o notepad++, sinó amb CLI). vi/vim ho pot fer:

:%s/lampara/làmpara/g

on %s és la comanda de substitució del vi

Com fer-ho automàticament per a tots els fitxers? (TBD)

Altres referències

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
IES Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines