PHP: usare le regular expression – parte 1
This entry was posted on August 26th, 2009 and is filed under php.
Ho già parlato di Regular Expression su questo sito, ma mai approfonditamente quando si parla di PHP. Ho notato che in italiano le risorse a disposizione per chi vuole usarle sono molto poche quindi ho deciso di trattare l’argomento.
Un pò il caldo, un pò i troppi impegni estivi ho scritto questo articolo in più giorni e, ho notato che un paio di giorni fa, mentre il mio era under construction, Noupe ha pubblicato articolo simile a questo link.
Come già fatto in un precedente articolo sull’argomento, prima di iniziare dò una definizione (fonte: Wikipedia) di Regular Expression:
Le espressioni regolari (in inglese regular expression, che può trovarsi abbreviata in regexp, regex o RE) sono sintassi attraverso le quali si possono rappresentare insiemi di stringhe. Gli insiemi caratterizzabili con espressioni regolari sono anche detti linguaggi regolari (e coincidono con quelli generabili dalle grammatiche regolari e riconoscibili dagli automi a stati finiti).
Una volta capito cos’è una regular expression si può definire la sintassi delle espressioni e gli operatori che usa:
^ Inizio stringa
$ Fine stringa
[a-z] Ogni lettera compresa tra a e z in minuscolo
[A-Z] Ogni lettera compresa tra A e Z in maiuscolo
[0-9] Numeri da 0 a 9
[^0-9] Escludi i numeri da 0 a 9
[^A-G] Escludi i caratteri in maiuscolo tra A e G
? Zero o una ripetizione dell’espressione che lo precede
* Zero o più ripetizioni dell’espressione che lo precede
+ Una o più ripetizioni dell’espressione che lo precede
{2} Esattamente due ripetizioni dell’espressione che lo precede
{2,} Due o più ripetizioni dell’espressione che lo precede
{2,4} Tra due e quattro ripetizioni dell’espressione che lo precede
. Ogni carattere
(a|b) a OR b
\s Spazio vuoto
Qualche semplice esempio per capire come usarle:
^foo Stringa che inizia con “foo”
foo$ Stringa che termina con “foo”
[a-zA-Z0-9]? Zero o una ripetizione di stringa contenente maiuscole, minuscole e numeri. (Altri caratteri non matchano con l’espressione)
[^0-9]{2,4} Tra due e quattro ripetizioni di stringa contenente caratteri diversi da quelli numerici
Consiglio sempre di fare qualche prova per vederle all’opera e capire la loro potenza in ogni suo uso.
Bene. Ora che abbiamo capito cos’è una regular expression e come si usa per estrarre informazioni da una stringa, possiamo incominciare a presentare le funzioni che il PHP offre per la sua manipolazione e spiegarne il funzionamento.
Le Abbreviazioni PHP
Le abbreviazioni PHP della sintassi pocanzi spiegata sono:
\d = [0-9] (digit)
\D = [^0-9] (digit esclusi)
\w = [0-9A-Za-z] (tutti i caratteri esclusi i simboli)
\W = [^0-9A-Za-z] (solo simboli)
\s = [ \t\n\r] (caratteri di spaziatura)
\S = [^ \t\n\r] (esclusi caratteri di spaziatura)
i = ignora case sensitive
m = modalità multilinea
u = pattern in UTF-8
Quindi possiamo sfruttare le abbreviazioni anche per evitare di fare errori di scrittura della nostra espressione.
Le funzioni PHP
Le funzioni PHP per gestire le regular expression sono suddivise in tre set:
- preg Function Set
- eregi Funciont Set
- mb_eregi Function Set
In questo articolo tratteremo solo il primo set, anche per dare modo di familiarizzare con i diversi set a disposizione. Gli altri due set verranno analizzati nella seconda parte.
preg Function Set
Il set di funzioni “preg” usano una sintassi Perl-compatibile nella gestione delle espressioni regolari. In Perl un’espressione regolare è delimitata da ‘/regex/’, quindi una qualsiasi espressione vorremmo identificare nelle nostre funzioni dovrà essere delimitata dagli slash. Le funzioni fornite dal PHP sono:
- preg_filter
- preg_grep
- preg_last_error
- preg_match_all
- preg_match
- preg_quote
- preg_replace
- preg_replace_callback
- preg_split
Tra quelle elencate, sicuramente le più usate in assoluto sono la numero 5 e la numero 7. Vediamole però tutte in azione, in maniera da capire cosa fanno e come usarle, incominciando però dalla numero 5 anzichè dalla numero 1. Il perchè è semplice, essendo le funzioni più usate, molte delle altre sono una estensione di queste due.
5. preg_match()
Questa funzione restituisce un booleano che indica se il pattern è contenuto nella stringa. Il prototipo è il seguente:
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags [, int $offset ]]] )
Il primo parametro conterrà il pattern, cioè la regular expression da identificare, il secondo la stringa su cui verificarne l’esistenza.
$string = 'Lorem ipsum dolor sit amet'; echo preg_match( '/^lorem/i', $string);
Il pattern identifica tutte le stringhe che iniziano con il token “lorem”. Il termine “i” alla fine della regex sta ad indicare che non ci interessa se il termine è in maiuscolo o in minuscolo.
7. preg_replace()
Questa funzione ci consente di sostituire, all’interno di una stringa, l’espressione regolare con un’altra a nostra scelta. Il suo prototipo è il seguente:
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit= -1 [, int &$count ]] )
I tre parametri più importanti sono $pattern, $replacement e $subject. Come dicono i nomi il primo parametro conterrà la regular expression, mentre il secondo conterrà la stringa da sostituire e il terzo la stringa su cui applicare la regola. I token identificati nella regular expression vengono identificati all’interno di $replacement con $1, $2, $3, … nella sequenza in cui si trovano nel pattern.
Vediamo un esempio per chiarirci le idee:
$string = 'Lorem ipsum dolor sit amet';
echo preg_replace("/^(\w+)/","<strong>$1</strong>",$string);
La funzione non fa altro che restituire il primo termine della stringa in grassetto. \w ho spiegato pocanzi che sta ad indicare tutti i caratteri esclusi i simboli (e ovviamente gli spazi ma era sottinteso).
Riprendiamo ora in ordine di numerazione la spiegazione delle prossime funzioni.
1. preg_filter()
Questa funzione è presente nelle versioni PHP dalla 5.3.0 in poi quindi attenzione ad utilizzarla. E’ identica alla preg_replace con l’unica differenza che essa restituisce solo gli elementi che fanno match con il pattern. Ad esempio se passassimo un array di stringhe, esso restituirà solo gli elementi dell’array che fanno match con il pattern.
2. preg_grep()
Questa funzione è simile alla precedente. In pratica prende in ingresso un array di elementi e ne restituisce uno con solo gli elementi che fanno match. Il suo prototipo è il seguente:
array preg_grep ( string $pattern , array $input [, int $flags= 0 ] )
Se $flags è posta ad 1 restituisce l’inverso, ovvero l’array degli elementi che NON matchano.
3. preg_last_error()
Questa funzione è presente nelle versioni PHP dalla 5.2.0 in poi quindi attenzione ad utilizzarla. Restituisce, se verificato, l’errore dell’ultima esecuzione di una regex.
4. preg_match_all()
Simile alla preg_match solo che restituisce il numero di occorrenze e, salva in un array le singole occorrenze. Il prototipo è il seguente:
int preg_match_all ( string $pattern , string $subject , array &$matches [, int $flags [, int $offset ]] )
Un esempio:
$pattern = "/\(? (\d{3})? \)? (?(1) [\-\s] ) \d{3}-\d{4}/x";
$subject = "Call 555-1212 or 1-800-555-1212 12-234";
echo preg_match_all($pattern,$subject,$phones);
print_r($phones);
Il seguente codice trova le occorrenze di numeri di telefono (americani) e li salva nell’array $phones. Il risultato della funzione sarà 2, ovvero il numero di occorrenze che fanno match con il pattern, mentre stampando $phones vedremo che contiene i numeri identificati.
6. preg_quote()
Funzione che consente di inserire uno slash “/” all’interno di una stringa quando si presentano caratteri o metadati che potrebbero essere confusi con quelli utilizzati dalle regex. Se vogliamo sostituirli con altri simboli che non siano lo / è sufficiente aggiungerli come secondo parametro alla funzione.
8. preg_replace_callback()
Funzione identica alla preg_replace() con l’unica differenza che anzichè passare un “rimpiazzo” viene passato un “callback”. Il prototipo è il seguente:
mixed preg_replace_callback ( mixed $pattern , callback $callback , mixed $subject [, int $limit= -1 [, int &$count ]] )
Per callback si intende una funzione che abbia come risultato una stringa o un’array da usare come replacement.
9. preg_split()
Funzione che inserisce in un array le stringhe che matchano con il pattern.
La prima parte dell’articolo si chiude qui. Nella seconda parte analizzeremo gli altri due set di funzioni che il PHP ci fornisce per gestire le regular expression e includerò alcuni esempi di espressioni regolari più elaborate e che sicuramente risulteranno molto utili.














November 26, 2009 at 11:15 am
Ciao Simone e complimenti per la guida
Con WordPress, ho trovato un plugin in grado di creare in automatico thumbnail per il mio video blog. Con la funzione preg_match trova il video YT embed nel corpo del post e, prelevandone solo l’ID, crea un custom field con il link al thumbnail del video stesso. Sfortunatamente, io inserisco i video non nel corpo del post ma utilizzando un custom field con nome “embed”.
Come posso cambiare il codice per far prelevare il cod. del video youtube da custom field?
Spero di essere stato chiaro… grazie sin d’ora
<?php add_action('save_post','find_ytid', 10, 2); function find_ytid($postID, $post) { if($parent_id = wp_is_post_revision($postID)) { $postID = $parent_id; } $content = $_POST['content']; if (preg_match('/http:\/\/www.youtube\.com\/v\/([a-zA-Z0-9\-\_]{11})/', $content, $yturl) !='') { $ytid = substr($yturl[0], 25, 31); $custom = 'http://img.youtube.com/vi/'.$ytid.'/hqdefault.jpg'; update_custom_meta($postID, $custom ,'ytthumb_url'); } elseif (preg_match('/http(v|vh|vhd):\/\/([a-zA-Z0-9\-\_]+\.|)youtube\.com\/watch(\?v\=|\/v\/)([a-zA-Z0-9\-\_]{11})([^November 26, 2009 at 11:51 am
Ciao Andrea e benvenuto sul blog.
Sinceramente non so come funzioni l’embed di YouTube e che differenze ci siano con quello da te utilizzato. Il codice che hai allegato è anche stato tagliato quindi mi sono perso tutto il ramo elseif(). Ti consiglio di sentirci in privato, mandami una mail, e di spiegarmi per bene il problema e soprattutto di non lasciare in giro porzioni di codice e link al sito dove le usi, ne va della tua sicurezza!
Attendo tue notizie.
Ciao
July 16, 2010 at 10:21 pm
Ciao Simone, mi chiamo come te!
Ho un problemino con la funzione preg_replace.
Io l’ho usata nel seguente modo:
echo preg_replace('/^~+[a-zA-Z0-9]+~/','<em>$1</em>',"~Grassetto~");Mi stampa (lo vedo nel codice) i due tag e ma non il testo. Come mai? Come posso risolvere?
Grazie mille
July 17, 2010 at 8:52 am
Ciao Simone,
c’è solo un errore di parentesi all’interno della regex. Quella corretta è la seguente:
echo preg_replace('/^~+([a-zA-Z0-9]+)~/', '<em>$1</em>','~Grassetto~');Ciao!
July 17, 2010 at 1:34 pm
Grazie mille!
Un ultima cosa:
$stringa=preg_replace('/\n$/', "<p>\\1</p>", $stringa);Dove sbaglio?
Scusami ancora, ma nel campo delle RegEx sono un principiante
July 17, 2010 at 2:31 pm
Se non mi dici cosa dovrebbe fare l’espressione non posso aiutarti.
Intanto posso dirti che magari dovresti mettere $1 per indicare il primo token al posto di \\1 nel secondo parametro della funzione. Però se non mi dici cosa dovrebbe fare..
July 17, 2010 at 3:34 pm
Oops, scusami tanto. Vorrei fare in modo che ogni volta che trovi nella stringa passata un invio a capo (quindi \n) mi apra e chiuda un paragrafo html.
Scusami, non ho capito un’ultima cosa: che differenza c’è tra \\1 e $1? Perchè in alcune guide ho visto scritto \\1 mentre in altre $1…
July 17, 2010 at 3:50 pm
Il PHP ha due set per le regex:
1. preg_ che sono quelle di questo articolo
2. ereg_ che sono quelle della seconda parte dell’articolo
Il set preg_ gestisce i token con $, il set ereg_ con \\ quindi non puoi mischiare le due cose.
Comunque a prescindere da questo errore, da come hai fatto la tua regex, nel caso funzionasse trasformerebbe un \n in < p>\n< /p>. Cioè in pratica cerca solo lo \n ignorando del tutto la stringa.
July 17, 2010 at 3:58 pm
Bhe…l’unica regolarità nel rimando a capo è quella. Tu cosa mi suggerisci di fare?
July 17, 2010 at 4:09 pm
Devi fare qualcosa del tipo:
([a-zA-Z0-9]+)\n
che diventa:
< p >$1 < / p>
E’ solo un esempio quindi non completa. Adattala alla tua effettiva esigenza.
July 17, 2010 at 4:12 pm
Grazie mille, io l’ho ulteriormente semplificato così
Grazie ancora e complimentoni!
July 17, 2010 at 4:30 pm
Hai fatto benissimo,
se deve accettare qualsiasi carattere è la scelta migliore!
Ciao
July 21, 2010 at 5:26 pm
Salve. Innanzitutto complimenti per il blog, ci sono molte guide utilissime.
A proposito di preg_replace, è da due giorni che ho un problemino. Utilizzo la funzione per convertire i bbcode [ img ] [ /img ] per far visualizzare le immagini all’interno dei messaggi, di un piccolo forum da me creato.
Avrei anche la necessità di controllare che l’immagine inserita non vada oltre alle misure da me stabilite, soprattutto in larghezza. Per il ridimensionamento automatico delle immagini credo di aver risolto il problema, creando una funzione che me le ridimensioni nel caso superassero le misure consentite. Il problema si pone quando devo associare questa funzione al bbcode. Io, nella mia ignoranza, ho provato a fare una cosa del genere:
$post[message] = preg_replace_callback("#\[img\](http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?){1}\[/img\]#", OutThumb($1, $wmax, $hmax), $post[message]);OutThumb sarebbe la funzione che dovrebbe ridimensionare l’immagine e purtroppo così non funziona. Che consiglio mi dai?! Grazie, se risponderai!!