197 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #ifndef __REGEXP_H
 | |
| #include <regexp.h>
 | |
| #endif           
 | |
| 
 | |
| // codici di ritorno della matche()
 | |
| #define regexp_MATCH_PATTERN (6) // pattern non valido
 | |
| #define regexp_MATCH_LITERAL (5) // il pattern non coincide su un carattere comune
 | |
| #define regexp_MATCH_RANGE   (4) // il pattern non coincide in un costrutto [..]
 | |
| #define regexp_MATCH_ABORT   (3) // il stringa da confrontare è terminata anticipatamente
 | |
| #define regexp_MATCH_END     (2) // il pattern è terminato anticipatamente
 | |
| #define regexp_MATCH_VALID   (1) // pattern e stringa coincidono
 | |
| 
 | |
| // codici di ritorno della is_valid_pattern()
 | |
| #define regexp_PATTERN_VALID  (0) // il pattern è valido
 | |
| #define regexp_PATTERN_ESC   (-1) // è presente un escape aperto a fine pattern
 | |
| #define regexp_PATTERN_RANGE (-2) // c'è un range non chiuso all'interno di un costrutto [..]
 | |
| #define regexp_PATTERN_CLOSE (-3) // manca la parentesi di chiusura in un costrutto [..]
 | |
| #define regexp_PATTERN_EMPTY (-4) // c'è un costrutto vuoto
 | |
| 
 | |
| // prototipi delle funzioni interne
 | |
| HIDDEN int matche(const char *pat, const char *str); // ritorna un codice della classe regexp_MATCH che indica se e in che modo pattern e stringa coincidono
 | |
| HIDDEN int matche_after_star(const char *pat, const char *str); // chiama ricorsivamente la matche() con i segmenti puri del pattern e della stringa
 | |
| HIDDEN bool is_pattern(const char *pat); // ritorna TRUE se la stringa è un pattern
 | |
| HIDDEN bool is_valid_pattern(const char *pat, int *err= NULL); // ritorna TRUE se la stringa è un pattern valido, indica un codice di ritorno della classe regexp_PATTERN nel secondo parametro
 | |
| 
 | |
| HIDDEN bool is_pattern(const char *p) {
 | |
| 	while (*p) {
 | |
| 		switch (*p++) {
 | |
| 			case '?':
 | |
| 			case '*':
 | |
| 			case '[':
 | |
| 			case '\\':
 | |
| 			return TRUE;
 | |
| 		}
 | |
| 	}
 | |
| 	return FALSE;
 | |
| }
 | |
| 
 | |
| HIDDEN bool is_valid_pattern(const char *p, int *error_type) {
 | |
| 	if (error_type != NULL) *error_type= regexp_PATTERN_VALID; // inizializzazione del tipo d'errore
 | |
| 	while (*p) { // ciclo all'interno del pattern fino a fine stringa
 | |
| 		switch(*p) { // determinazione del tipo di wild card nel pattern
 | |
| 			case '\\': // controllo dell'escape, non può essere a fine pattern
 | |
| 				if (!*++p) {
 | |
| 					if (error_type != NULL) *error_type= regexp_PATTERN_ESC;
 | |
| 					return FALSE;
 | |
| 				}
 | |
| 				p++;
 | |
| 				break;
 | |
| 			case '[': // controllo della costruzione del costrutto [..]
 | |
| 				p++;
 | |
| 				if (*p == ']') { // se il prossimo carattere è ']' il costrutto è vuoto
 | |
| 					if (error_type != NULL) *error_type= regexp_PATTERN_EMPTY;
 | |
| 					return FALSE;
 | |
| 				}
 | |
| 				if (!*p) { // se si è a fine stringa il costrutto non è chiuso
 | |
| 					if (error_type != NULL) *error_type= regexp_PATTERN_CLOSE;
 | |
| 					return FALSE;
 | |
| 				}
 | |
| 				while (*p != ']') { // ciclo fino a fine costrutto [..]
 | |
| 					if (*p == '\\') { // controllo per gli escape
 | |
| 						p++;
 | |
| 						if (!*p++) { // controllo che l'escape non sia a fine pattern
 | |
| 							if (error_type != NULL) *error_type= regexp_PATTERN_ESC;
 | |
| 							return FALSE;
 | |
| 						}
 | |
| 					} else p++;
 | |
| 					if (!*p) { // se si è a fine stringa il costrutto non è chiuso
 | |
| 						if (error_type != NULL) *error_type= regexp_PATTERN_CLOSE;
 | |
| 						return FALSE;
 | |
| 					}
 | |
| 					if (*p == '-') { // controllo di un eventuale range
 | |
| 						if (!*++p || *p == ']') { // deve esistere una fine del range
 | |
| 							if (error_type != NULL) *error_type= regexp_PATTERN_RANGE;
 | |
| 							return FALSE;
 | |
| 						} else {
 | |
| 							if (*p == '\\') p++; // controllo degli escape
 | |
| 							if (!*p++) { // controllo che l'escape non sia a fine pattern
 | |
| 								if (error_type != NULL) *error_type= regexp_PATTERN_ESC;
 | |
| 								return FALSE;
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 			case '*': // tutti gli altri caratteri sono elementi validi del pattern
 | |
| 			case '?':
 | |
| 			default:
 | |
| 				p++; // caratteri normali
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| HIDDEN int matche_after_star(const char *p, const char *t) {
 | |
| 	int match= 0;
 | |
| 	while (*p == '?' || *p == '*') { // salto degli eventuali '*' e '?'
 | |
| 		if (*p == '?') // salto di un carattere per ciascun '?'
 | |
| 			if (!*t++) return regexp_MATCH_ABORT; // se la stringa termina qui non c'è coincidenza
 | |
| 		p++; // posizionamento sul prossimo carattere del pattern
 | |
| 	}
 | |
| 	if (!*p) return regexp_MATCH_VALID; //se il pattern è concluso c'è coincidenza
 | |
| 	int nextp= *p; // prelevamento del prossimo carattere, normale o '['
 | |
| 	if (nextp == '\\') {
 | |
| 		nextp= p[1];
 | |
| 		if (!nextp) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido
 | |
| 	}
 | |
| 	do { // ciclo fino a conclusione di stringa o pattern
 | |
| 		if (nextp == *t || nextp == '[') match= matche(p, t); // è necessario che il carattere corrente del testo coincida con il carattere corrente del pattern, oppure che il pattern abbia un inizio di costrutto [..]
 | |
| 		if (!*t++) match= regexp_MATCH_ABORT; // se la stringa termina qui non c'è coincidenza
 | |
| 	} while (match != regexp_MATCH_VALID && match != regexp_MATCH_ABORT && match != regexp_MATCH_PATTERN);
 | |
| 	return match; // ritorno del risultato
 | |
| }
 | |
| 
 | |
| HIDDEN int matche(const char *p, const char *t) {
 | |
| 	for (; *p; p++, t++) {
 | |
| 		if (!*t) // se si è alla fine della stringa, il confronto è concluso
 | |
| 			return (*p == '*' && *++p == '\0') ? regexp_MATCH_VALID : regexp_MATCH_ABORT;
 | |
| 		switch (*p) { // determina il tipo di wild card del pattern
 | |
| 			case '?': // carattere singolo, qualunque carattere coincide
 | |
| 				break;
 | |
| 			case '*': // sottostringa, coincide qualunque sequenza di caratteri
 | |
| 				return matche_after_star (p, t);
 | |
| 			case '[': { // costrutto [..], controllo di coincidenza per inclusione o esclusione su un solo carattere
 | |
| 				p++; // posizionamento all'inizio del range
 | |
| 				bool invert= FALSE; // controllo di inclusione o esclusione del costrutto
 | |
| 				if (*p == '!' || *p == '^') {
 | |
| 					invert= TRUE;
 | |
| 					p++;
 | |
| 				}
 | |
| 				if (*p == ']') // se si è su una chiusura di costrutto il pattern non è valido
 | |
| 					return regexp_MATCH_PATTERN;
 | |
| 				bool member_match= FALSE;
 | |
| 				bool loop= TRUE;
 | |
| 				while (loop) {
 | |
| 					char range_start, range_end; // inizio e fine del range corrente
 | |
| 					if (*p == ']') { // se si è alla fine del costrutto il ciclo si conclude
 | |
| 						loop= FALSE;
 | |
| 						continue;
 | |
| 					}
 | |
| 					if (*p == '\\') // controllo di coincidenza su un metacarattere, dopo un escape
 | |
| 						range_start= range_end= *++p;
 | |
| 					else
 | |
| 						range_start= range_end= *p;
 | |
| 					if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina non è valido
 | |
| 					if (*++p == '-') { // controllo del segno di sottoinsieme
 | |
| 						range_end= *++p; // impostazione della fine del range
 | |
| 						if (range_end == '\0' || range_end == ']') return regexp_MATCH_PATTERN; // se il costrutto [..] o il pattern terminano qui allora il pattern non è valido
 | |
| 						if (range_end == '\\') { // la fine del range è un metacarattere
 | |
| 							range_end= *++p;
 | |
| 							if (!range_end) return regexp_MATCH_PATTERN; // se il pattern termina non è valido
 | |
| 						}
 | |
| 						p++; // posizionamento oltre il range
 | |
| 					}
 | |
| 					if (range_start < range_end) { // confronto del carattere corrente con il costrutto, controllo della sequenzialità degli estremi del range
 | |
| 						if (*t >= range_start && *t <= range_end) {
 | |
| 							member_match= TRUE;
 | |
| 							loop= FALSE;
 | |
| 						}
 | |
| 					} else {
 | |
| 						if (*t >= range_end && *t <= range_start) {
 | |
| 							member_match= TRUE;
 | |
| 							loop= FALSE;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				if ((invert && member_match) || !(invert || member_match)) // controllo del risultato dell'ultimo confronto nel costrutto [..]
 | |
| 					return regexp_MATCH_RANGE;
 | |
| 				if (member_match) { // salto del resto del costrutto se non è esclusivo
 | |
| 					while (*p != ']') {
 | |
| 						if (!*p) return regexp_MATCH_PATTERN; // se si è a fine pattern il costrutto non è valido
 | |
| 						if (*p == '\\') { // salto di un confronto con un metacarattere
 | |
| 							p++;
 | |
| 							if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido
 | |
| 						}
 | |
| 						p++; // posizionamento sul prossimo carattere del pattern
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 			}
 | |
| 			case '\\': // confronto con un metacarattere
 | |
| 				p++; // posizionamento sul carattere da confrontare
 | |
| 				if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido
 | |
| 			default: // confronto con un carattere normale
 | |
| 				if (*p != *t) return regexp_MATCH_LITERAL;
 | |
| 		}
 | |
| 	}
 | |
| 	if (*t) return regexp_MATCH_END; // se la stringa non è conclusa non c'è coincidenza
 | |
| 	else return regexp_MATCH_VALID;
 | |
| }
 | |
| 
 | |
| bool match(const char *pat, const char *str) {
 | |
| 	int err= matche(pat, str);
 | |
| 	return (err == regexp_MATCH_VALID); // ritorna TRUE se il pattern e la stringa coincidono
 | |
| }
 |