/* * PATMAT.C - Pattern matching. * * Written November 29, 1988 by Sreenath Chary. Minor maintenance on * December 21, 1996 by Andrew Clarke. Released to the public domain. * * Pass two string pointers as parameters. The first being a raw * string and the second a pattern the raw string is to be matched * against. If the raw string matches the pattern, the function returns * 1, otherwise it returns 0. * * patmat("abcdefghi", "*ghi") returns 1 * patmat("abcdefghi", "??c??f*") returns 1 * patmat("abcdefghi", "*dh*") returns 0 * patmat("abcdefghi", "*def") returns 0 * * The asterisk is a wildcard to allow any characters from its first * appearance to the next specific character. The character ? is a * wildcard for only one character in the position it appears. * * Combinations such as "*?" or "?*" or "**" are illegal for obvious * reasons, and the functions may goof, although I think it will still * work. * * The only simple way I could devise is to use recursion. Each * character in the pattern is taken and compared with the character in * the raw string. If it matches then the remaining amount of the * string and the remaining amount of the pattern are passed as parameters * to patmat again until the end of the pattern. If at any stage the * pattern does not match, then we go back one level and at this level * if the previous character was an asterisk in the pattern, we hunt * again from where we left off, otherwise we return back one more level * with a not found and the process goes on till the first level call. * * Only one character at a time is considered, except when the character * is an asterisk. You'll get the logic as the program unfolds. */ #include #include "patmat.h" int patmat(char *raw, char *pat) { /* if pointed to one, then match (both NULL also) */ if ( pat==raw ) { return 1; } /* if only one is NULL, then mismatch */ if ( !pat || !raw ) { return 0; } /* if it's the end of both strings, then match */ if (*pat == '\0' && *raw == '\0') { return 1; } /* if it's the end of only pat, then mismatch */ if (*pat == '\0') { return 0; } /* if pattern is a '*' */ if (*pat == '*') { unsigned int i; /* match patterns *?****???***?? faster... */ while (*(++pat)) if (*pat == '*') { /* do nothing */ } else if (*pat == '?') { if (*raw) ++raw; else return 0; } else break; /* if it is the end of pat, then match */ if (*pat == '\0') { return 1; } /* else hunt for match or wildcard */ for (i = 0; i <= strlen(raw); i++) { if (*(raw + i) == *pat || *pat == '?') { /* if found, match rest of pat */ if (patmat(raw + i + 1, pat + 1) == 1) { return 1; } } } } else { /* if end of raw, then mismatch */ if (*raw == '\0') { return 0; } /* if chars match then try and match the rest of it */ if (*pat == '?' || *pat == *raw) { if (patmat(raw + 1, pat + 1) == 1) { return 1; } } } /* fell through, no match was found */ return 0; } #ifdef TEST #include int main(void) { printf("patmat(\"abcdefghi\", \"*ghi\"): %d\n", patmat("abcdefghi", "*ghi")); printf("patmat(\"abcdefghi\", \"??c??f*\"): %d\n", patmat("abcdefghi", "??c??f*")); printf("patmat(\"abcdefghi\", \"*dh*\"): %d\n", patmat("abcdefghi", "*dh*")); printf("patmat(\"abcdefghi\", \"*def\"): %d\n", patmat("abcdefghi", "*def")); return 0; } #endif