diff --git a/include/regexp.cpp b/include/regexp.cpp new file mode 100755 index 000000000..e1902d8f8 --- /dev/null +++ b/include/regexp.cpp @@ -0,0 +1,196 @@ +#ifndef __REGEXP_H +#include +#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 +} diff --git a/include/regexp.h b/include/regexp.h new file mode 100755 index 000000000..7d79422aa --- /dev/null +++ b/include/regexp.h @@ -0,0 +1,30 @@ +#ifndef __REGEXP_H +#define __REGEXP_H + +#ifndef __STDTYPES_H +#include +#endif + +#ifndef NULL +#include +#endif + +// Composizione delle regular expression: +// ------------------------------------- +// - '*' sostituisce una qualunque sottostringa (0 o più caratteri) +// - '?' sostituisce un carattere qualunque (necessariamente presente) +// - [RANGE] sostituisce un carattere presente nel RANGE specificato +// I range si compongono di singoli caratteri o di sottoinsiemi di caratteri, +// indicati con un carattere iniziale, un segno meno ('-') e un carattere +// finale. Esempio [0-9a-fL] comprende i caratteri dallo '0' al '9', dalla 'a' +// alla 'z' e la lettera 'L'. I range possono essere prefissati da '!' o +// '^' per indicare che l'insieme dei caratteri specificati sono esclusi +// e non inclusi. Esempio [!jkwxy] indica la sostituzione di qualunque +// carattere tranne 'j', 'k', 'w', 'x', 'y' e 'z'. +// Per specificare nei pattern gli stessi metacaratteri con cui si formano i +// pattern basta prefissarli con l'escape '\'. Esempio [\[\]] sostituisce un +// carattere di parentesi quadra aperta o chiusa. + +bool match(const char *pat, const char *str); // ritorna TRUE se il pattern (primo parametro) e la stringa (secondo) coincidono + +#endif diff --git a/include/strings.cpp b/include/strings.cpp index 3dde963c7..258fe6f97 100755 --- a/include/strings.cpp +++ b/include/strings.cpp @@ -315,20 +315,6 @@ int TString::find( return p ? int(p - _str) : -1; } -// Certified 50% -// @mfunc Confronta usando i caratteri jolly -bool TString::match( - const char* s) const // @parm Stringa da confrontare - - // @comm Confronta se la stringa e' parzialmente uguale ad un'altra, cioe' non confrontando - // tutti i caratteri, ma solo quelli non jolly -{ - if (strchr(s, '?') == NULL) return operator ==(s); - - for (const char* me = _str; *s && *me; s++, me++) - if (*s != '?' && *s != *me) break; - return *s == '\0' && *me == '\0'; -} #if XVT_OS != XVT_OS_WIN HIDDEN char* strstr(const char* string1, const char* string2) diff --git a/include/strings.h b/include/strings.h index c6a21130b..d41a401d4 100755 --- a/include/strings.h +++ b/include/strings.h @@ -9,6 +9,11 @@ #include #endif +#ifndef __REGEXP_H +#include +#endif + + // @doc EXTERNAL // @class Classe per la definizione della stringhe @@ -222,8 +227,9 @@ public: // @cmember Controlla se una stringa e piu' corta o uguale ad un'altra bool operator <=(const char* s) const { return strcmp(_str, s) <= 0; } - // @cmember Confronta usando i caratteri jolly - bool match(const char* s) const; + // @cmember Confronta usando le regular expression + bool match(const char* pat) const + { return ::match(pat, _str); } // @cmember Compara due stringhe (o i primi max caratteri) int compare(const char* s, int max = -1, bool ignorecase = FALSE) const; };