On 8/16/2018 2:56 PM, Anton Shepelev wrote:
> Please, publish your entries as immediate replies to this
> message in order to facilitate cohesion.
Solution #1.
My first solution is a non-recursive one, and should deal
with strings of any length and any combination of * ? and
regular letters without any consumption of RAM. It is al-
gorithmic, and proceeds logically through the wildcard
pattern to find the match.
Note: I've edited it down so it fits on these posts formatted.
It normally is simply wide / extended well beyond 80 columns in
places:
int wcmemcmp(const char *l, const char *r, size_t len)
{
size_t i;
// Iterate through each character, recognizing l[n] can have
// question marks to allow anything
for (i = 0; i < len; ++i)
{
// We skip ? characters, and fail on mismatches
if (l[i] != '?' && l[i] != r[i])
return(-1); // Fail
}
// If we get here, it matched
return(0);
}
// The logic / reasons why is in the comments. It goes through
// the process systematically, accounting for each thing as it
// goes. I pass in needleLength and haystackLength to allow for
// non-string-only compares.
int wcmatch1(const char *needle, const char *haystack,
int needleLength, int haystackLength)
{
// ni=needle iterator, hi=haystack iterator
int ni, hi, matchLength, lnResult;
// Make sure our environment is sane
if (!needle || !haystack)
return(0);
// Iterate through the needle, matching as long as we match
for (ni = 0, hi = 0; ni < needleLength; ++ni, ++hi)
{
// Grab this part of the needle we're searching for
switch (needle[ni])
{
case '*':
// Are we at the end of the needle?
if (ni == needleLength - 1)
return(1); // Everything after can match,
// so it's a match
// Look after the * to see what's there
for (++ni; ni < needleLength; )
{
// Repeating asterisks?
if (needle[ni] == '*')
{
// Skip repeating asterisks
++ni;
continue;
}
// We're past wildcards, so we must match
// whatever's from here until the next wc
if (haystack[hi] == 0)
return(0); // Failure, looking for ?
// beyond end of haystack
// Count the length of non-wildcard characters
// in the needle
for (matchLength = 0;
ni + matchLength < needleLength
&& needle[ni + matchLength] != '*'; )
++matchLength;
// Was this the end of the needle?
if (ni + matchLength == needleLength)
{
// We have to find the tail, it's like
// "*n" matching "anton"
if (hi + matchLength > haystackLength)
return(0); // There isn't enough
// room for it to match
// See if it's there at the end
return(wcmemcmp(needle + ni,
haystack
+ haystackLength
- matchLength,
matchLength) == 0);
}
// We must find this many matching characters
for (lnResult = -1;
hi <= haystackLength - matchLength;
++hi)
{
// Is this a match?
if ((lnResult = wcmemcmp(needle + ni,
haystack + hi,
matchLength)) == 0)
break; // Yes
}
// Did we find it?
if (lnResult != 0)
return(0); // No
// Skip past it in both
ni += matchLength - 1;
hi += matchLength - 1;
// We're done at this level, continue on
break;
}
// If we've reached the end of the needle string, and
// the last one was an asterisk, we accept anything
if (needle[ni] == 0 && needle[ni - 1] == '*')
return(1);
// Keep going
break;
case '?':
// This character is always a match if there's room
// in the haystack
if (haystack[hi] == 0)
return(0); // Failure, looking for ? beyond
// end of haystack
break;
default:
// Must match exactly
if (haystack[hi] == 0 || needle[ni] != haystack[hi])
return(0);
break;
}
}
// If we get here, it matched all the way through so far
return(needle[ni] == 0 && haystack[hi] == 0);
}
--
Rick C. Hodgin