[C] espressioni regolari

Area di discussione libera.

Moderatore: Staff

Regole del forum
1) Rispettare le idee altrui.
2) Evitare le offese dirette.
3) Leggere attentamente le risposte ricevute
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

[C] espressioni regolari

Messaggio da Dani »

Da un programma in C mi collego ad uno di quei siti che mostrano il proprio ip, richiedo e ricevo quindi la pagina html.
Il mio problema è riuscire ad estrapolare da tutto il sorgente html il mio ip.
Basandomi su una determinata pagina e guardando l'html è semplice, ma vorrei una soluzione universale, che vada bene con questo o quell'host.
Grazie :)

Avatar utente
gallows
Staff
Staff
Messaggi: 3471
Iscritto il: lun 20 set 2004, 0:00
Desktop: cwm
Distribuzione: OpenBSD
Località: ~/
Contatta:

Messaggio da gallows »


Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Messaggio da Dani »

Ho scritto un paio di righe, ma evidentemente mi sfugge qualcosa...

Codice: Seleziona tutto

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <regex.h>
#include <string.h>
#include <stdlib.h>

int main (int argc, char **argv)
{

char str[] = "xxxHello worldip 12.34.56.78abc hello !!!";
char pat[] = "[0-255]\\.[0-255]\\.[0-255]\\.[0-255]";
char *smatch;

regex_t compile;
regmatch_t first_match;
int retval, set;


if (regcomp (&compile, pat, REG_EXTENDED)) {
	fprintf (stderr, "regcomp() failed !\n");
	_exit (1);
	}

if ((retval = regexec (&compile, str, 1, &first_match, 0)) == REG_NOMATCH) {
	fprintf (stdout, "No match found in str !\n");
    _exit (0);
	}
	
else if (retval) {
	fprintf (stderr, "regexec() failed !\n");
	_exit (1);
	}
				
regfree (&compile);

set = first_match.rm_eo - first_match.rm_so; /* end offset - start offset */
smatch = (char*) malloc (set + 1);
strncpy (smatch, str + first_match.rm_so, set);
fprintf (stdout, "Match found: \"%s\"\n", smatch);
return 0;
}

Perchè non trova nulla nella stringa ?

Avatar utente
gallows
Staff
Staff
Messaggi: 3471
Iscritto il: lun 20 set 2004, 0:00
Desktop: cwm
Distribuzione: OpenBSD
Località: ~/
Contatta:

Messaggio da gallows »

Il pattern è bagliato, devi capire che l'analisi viene fatta carattere per carattere.
Ecco un esempio (non perfetto) che potrebbe funzionare nel tuo caso:

Codice: Seleziona tutto

    char  pattern[] = "([0-9]{1,3}\\.){,3}([0-9]{1,3})";                       
Come capita nelle regex non si capisce un bel niente, ma provo a spiegartelo:
{n,m} dice che la precedente regex può essere ripetuta un minimo di n volte per un massimo di m.
Quindi ([0-9]{1,3}\\.){,3} rappresenta un pattern del tipo NUM.NUM.NUM. il resto ([0-9]{1,3}) indica l'ultima parte dell'ip.
Come puoi vedere può prendere un match del tipo: 400.1.2.3.4 che NON è un IP valido, ma il mio esempio era solo per farti comprendere il funzionamento.

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Messaggio da Dani »

Quindi per evitare di prendere anche i valori > 255 devo passare l'occorrenza magari ad una mia funzione e fare una verifica, se tutti i pezzi della stringa convertiti in int sono < 255 posso interrompere la ricerca altrimenti continuo...Solo che non so se e' conveniente tutto questo :!:

Avatar utente
nuitari
Linux 3.x
Linux 3.x
Messaggi: 777
Iscritto il: dom 14 ott 2007, 12:51
Slackware: 12.0
Località: San Colombano al Lambro
Contatta:

Messaggio da nuitari »

era un esempio il suo... puoi fare una classe + complessa, che acetti per il primo valore o niente o un numero compreso fra 1 e 2.

Avatar utente
gallows
Staff
Staff
Messaggi: 3471
Iscritto il: lun 20 set 2004, 0:00
Desktop: cwm
Distribuzione: OpenBSD
Località: ~/
Contatta:

Messaggio da gallows »

Infatti, il controllo puoi eseguirlo direttamente con il pattern, in modo che eviti gli ip non validi. Mi viene in mente qualcosa del genere:

Codice: Seleziona tutto

    char pattern[] = "(2[0-5][0-5]\\.|1[0-9][0-9]\\.|[0-9]{1,2}\\.){3}"
                     "(2[0-5][0-5]|1[0-9][0-9]|[0-9]{1,2})"; 
In una stringa del tipo "invalid ip: 354.612.10.11, valid ip: 192.168.0.1" dovrebbe darti come match quello valido.

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Messaggio da Dani »

Ok, ho capito (oddio, si fa per dire...) , grazie mille.

Avatar utente
gallows
Staff
Staff
Messaggi: 3471
Iscritto il: lun 20 set 2004, 0:00
Desktop: cwm
Distribuzione: OpenBSD
Località: ~/
Contatta:

Messaggio da gallows »

DOH, leggo solo adesso un errore non da poco nel mio pattern.
Ho il fix pronto, ma secondo me è meglio che ci arrivi da solo. Anzi, mò faccio come i professori: «l'ho fatto di proposito per vedere se eri attento...» :)

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Messaggio da Dani »

Io vedo solo un'ammucchiata di numeri e strani caratteri :cry:

Avatar utente
gallows
Staff
Staff
Messaggi: 3471
Iscritto il: lun 20 set 2004, 0:00
Desktop: cwm
Distribuzione: OpenBSD
Località: ~/
Contatta:

Messaggio da gallows »

In pratica il mio pattern è sbagliato, perché 2[0-5][0-5]\\. salterebbe valori come 229.

Un pattern ancora migliore è:

Codice: Seleziona tutto

    char*  pattern = "((2[0-5][0-5]|2[0-4][0-9]|1[0-9][0-9]|"
                     "[1-9][0-9]|[0-9])\\.){3}(2[0-5][0-5]|2[0-4][0-9]|"        
                     "1[0-9][0-5]|[1-9][0-9]|[0-9])"
Cerco di tradurlo in linguaggio più umano:
Voglio una stringa che inizi con :

un 2 seguito da due numeri da 0 a 5 (ergo: 211, 240, ... sono ok)
OR
un 2 seguito da un numero inferiore a 5 e un'altro intero (249, 200, ...)
OR
un 1 seguito da due numeri interi (100, 192, ...)
OR
un numero da 1 a 9 seguito da un altro intero (10, 27, ...)
OR
un intero (1, 3, 7, ... )
AND
deve seguire un punto (255., 192., 10., 7., ...)
AND
questo pattern deve essere ripetuto per tre volte (192.168.0., 10.0.0., ...)

Poi c'è la stessa cosa senza il punto e senza ripetizione (192.168.0.1, 10.0.0.8, 82.0.5.4.3, ...)

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Messaggio da Dani »

Allucinante :shock:

Rispondi