| Autor: | Wojciech Muła |
|---|---|
| Dodany: | 8.03.2002 |
Artykuł omawia procedurę porównującą łańcuch ze wzorcem w którym użyto znaków wieloznacznych (ang. wildcards) znanych z DOS-a:
Przedstawione funkcje zostały przesłane na grupę dyskusyjną pl.comp.lang.c.
Gdy wzorzec zawiera tylko pytajniki sprawdzenie jest bardzo łatwe:
int str_quotcmp(const char *sring, const char* pattern)
{
char* s = (char*)string;
char* p = (char*)pattern;
while (*s && *p)
{
if ((*p != ?') && (*s != *p)) return 0;
s++;
p++;
}
return 1;
}
Jeśli jednak we wzorcu są gwiazdki (ang. asterisk) to sprawa nieco się komplikuje. Jak zostało napisane gwiazdka zastępuje dowolny ciąg liter, należy więc sprawdzić czy w łańcuchu istnieje taki fragment tekstu który będzie pasował do wzorca (poczynając od gwiazdki). Co jednak jeśli we wzorcu występuje większa liczba gwiazdek? — należy wziąć fragment wzorca spomiędzy dwóch kolejnych.
Proszę prześledzić przykład:
wzorzec = "as*ler*cor*r" łańcuch = "assembler corner"
Pierwszym fragmentem wzorca jest as — ponieważ nie ma przed nim gwiazdki musi on dokładnie pasować do początku łańcucha i tak jest.
wzorzec = "*ler*cor*r" łańcuch = "sembler corner"
Następnym fragmentem wzorca jest ler, przed nim występuje gwiazdka, czyli trzeba sprawdzić jego wszystkie możliwe położenia.
Najpierw porównany zostanie z fragmentem łańcucha sem — oczywiście nie pasuje. Następnie brane są kolejne 3-literowe fragmenty łańcucha: emb, ble, a w końcu ler który rzecz jasna jest identyczny.
wzorzec = "*cor*r" łańcuch = " corner"
Postępując tak samo jak wcześniej dojdziemy do wniosku, że łańcuch pasuje do wzorca.
Poniższa procedura zwraca 1 gdy łańcuch pasuje do wzorca.
int match_pattern(const char* string, const char* pattern)
{
char* p = (char*)pattern;
char* s = (char*)string;
char prev_asterisk;
char* asterisk;
int len;
while (*p)
{
if ((prev_asterisk = *p) == '*') p++; // jeśli bieżący znak jest gwiazdką
// przeskocz go (prev_asterisk
// przechowuje o tym informację)
if (!*p) break; // w przypadku gdy był to ostatni znak kończ
asterisk = strchr(p, '*'); // znajdź kolejne wystąpienie gwiazdki
// wyznacz długość fragmentu wzorca
if (asterisk) len = (int)asterisk-(int)p;
else {
len = strlen(p);
asterisk = &p[len];
}
if (prev_asterisk == '*') // sprawdzamy dowolną przerwę
{
char* temp = s;
while (*temp)
{
if (str_quotcmp2(p, temp, len)) break;
temp++;
}
if (!*temp) return 0; // jeśli doszliśmy do końca 'string'
// znaczy to, że fragment wzorca nie występuje
// w łańcuchu
p = asterisk;
s = temp+len;
}
else // bez przerw, dokładne dopasowanie
{
if (!str_quotcmp2(p, s, len)) return 0;
p = asterisk;
s+= len;
}
}
return 1;
}
Funkcja str_quotcmp2 jest taka sama jak przedstawiona na początku str_quotcmp, lecz jako warunek stopu została przyjęta długość fragmentu wzorca.
int str_quotcmp2(const char *sring, const char* pattern, int len)
{
char* s = (char*)string;
char* p = (char*)pattern;
while (*s && len)
{
if ((*p != '?') && (*s != *p)) return 0;
s++;
p++;
len--;
}
return (len == 0);
}