|
|
Comments and Discussions
|
|
 |

|
I read this article " ,its really amazing. I appreciate your efforts. I am student, I need help in defining the same kind of function according to my requirements. I hope, I 'll get good response.
Words are strings which are separated by dots. Two additional characters are also valid i.e:The *, which matches 1 word and the #, which matches 0..N words Example: *.stock.# matches the routing keys usd.stock and eur.stock.dsf but not stock.nasdaq.
Your help would be highly appreciated.
Sam
|
|
|
|
|

|
First of all I like this code, it is small and fully stand-alone.
I have modified it, because I need an additional wildcard joker that represents digits. Finally the modified function accepts '*', '?' and '#' as joker characters.
int wildcmp_ex(const char *wild, const char *string) {
const char *cp = NULL, *mp = NULL;
while (*string) {
if (*wild == '*') {
if (!*++wild) {
return 1;
}
mp = wild;
cp = string+1;
} else if (((*wild == *string) && (*wild != '#')) || (*wild == '?') || ((*wild == '#') && isdigit(*string))) {
wild++;
string++;
} else {
if (mp)
{
wild = mp;
string = cp++;
}
else
{
return 0;
}
}
}
while (*wild == '*') {
wild++;
}
return !*wild;
}
Thomas Haase
modified 29 Sep '11 - 8:26.
|
|
|
|

|
Hi Jack Handy,
Is there a licence attached to this code?
Thanks, Mark
|
|
|
|

|
Just for fun... a C# version with almost the same syntax as the original C version
public static bool wildcmp(string pattern, string text) {
var wild = new StringScanner(pattern);
var @string = new StringScanner(text);
var mp = wild;
var cp = @string;
while (@string && wild != '*') {
if (wild != @string && wild != '?') {
return false;
}
wild++;
@string++;
}
while (@string) {
if (@wild == '*') {
if (!++wild) {
return true;
}
mp = wild;
cp = @string + 1;
} else if (wild == @string || wild == '?') {
wild++;
@string++;
} else {
wild = mp;
@string = cp++;
}
}
while (wild == '*') {
wild++;
}
return !wild;
}
public struct StringScanner
{
private string _string;
private int _position;
public StringScanner(string s)
{
_string = s;
_position = 0;
}
public string String
{
get { return _string; }
}
public int Position
{
get { return _position; }
}
public bool Finished
{
get { return _position == _string.Length;}
}
public char Current
{
get { return Finished ? '\0' : _string[_position]; }
}
public bool MoveNext()
{
if (Finished)
return false;
_position++;
return true;
}
public static StringScanner operator ++(StringScanner scanner)
{
scanner.MoveNext();
return scanner;
}
public static StringScanner operator +(StringScanner scanner, int n)
{
return new StringScanner(scanner.String)
{
_position = Math.Min(scanner.Position + n, scanner.String.Length)
};
}
public static implicit operator bool(StringScanner scanner)
{
return !scanner.Finished;
}
public static implicit operator char(StringScanner scanner)
{
return scanner.Current;
}
public static bool operator ==(StringScanner scanner1, StringScanner scanner2)
{
return scanner1.Current == scanner2.Current;
}
public static bool operator !=(StringScanner scanner1, StringScanner scanner2)
{
return scanner1.Current != scanner2.Current;
}
}
|
|
|
|

|
I've been using this for years, just don't show it to your instructor.
BOOL wm(const char *s, const char *t)
{
return *t-'*' ? *s ? (*t=='?') | (toupper(*s)==toupper(*t)) && wm(s+1,t+1) : !*t : wm(s,t+1) || *s && wm(s+1,t);
}
If you want case sensitive, remove the toupper() calls.
|
|
|
|

|
This strikes me as an obvious place to use recursion. So here goes...
public class MString
{
public static bool CompareWWc(string strA, string strB, bool ignoreCase)
{
if (ignoreCase)
return CompareWWc(strA.ToLower(), strB.ToLower());
else
return CompareWWc(strA, strB);
}
public static bool CompareWWc(string strA, string strB)
{
for (int i = 0; i < strA.Length; i++)
{
if (strA[i] == '*')
{
if (i == strA.Length - 1)
return true;
strA = strA.Substring(i + 1); for (int j = i; j < strB.Length; j++)
if (CompareWWc(strA, strB.Substring(j)))
return true;
return false;
}
if (i >= strB.Length || (strA[i] != strB[i] && strA[i] != '?'))
return false;
}
return strA.Length == strB.Length;
}
}
And here's a little test sequence:
if (!MString.CompareWWc("", ""))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("something", "something"))
Console.WriteLine("Something wrong!");
if (MString.CompareWWc("something", "zomething"))
Console.WriteLine("Something wrong!");
if (MString.CompareWWc("something", "some"))
Console.WriteLine("Something wrong!");
if (MString.CompareWWc("something", "something else"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("s?m?th???", "something"))
Console.WriteLine("Something wrong!");
if (MString.CompareWWc("s?m?th???", "somethin"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("*", ""))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("*", "nonsense"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("non*", "nonsense"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("*nonsense", "nonsense"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("non*nse", "nonsense"))
Console.WriteLine("Something wrong!");
if (MString.CompareWWc("non*nse", "nonsenze"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("non*n?e", "nonsense"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("n*on*nse", "nonsense"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("n*n*nse", "nonsense"))
Console.WriteLine("Something wrong!");
if (MString.CompareWWc("*non*nse", "nonsenze"))
Console.WriteLine("Something wrong!");
if (!MString.CompareWWc("n*n*n?e", "nonsense"))
Console.WriteLine("Something wrong!");
}
By the way, the name CompareWWc means Compare With Wildcards.
|
|
|
|

|
Actually, the recursive function together with substring will make this slow.
I'm using this at the moment:
public static class StringExtensions
{
public static bool WildcardMatch(this string str, string compare, bool ignoreCase)
{
if (ignoreCase)
return str.ToLower().WildcardMatch(compare.ToLower());
else
return str.WildcardMatch(compare);
}
public static bool WildcardMatch(this string str, string compare)
{
if (string.IsNullOrEmpty(compare))
return str.Length == 0;
int pS = 0;
int pW = 0;
int lS = str.Length;
int lW = compare.Length;
while (pS < lS && pW < lW && compare[pW] != '*')
{
char wild = compare[pW];
if (wild != '?' && wild != str[pS])
return false;
pW++;
pS++;
}
int pSm = 0;
int pWm = 0;
while (pS < lS && pW < lW)
{
char wild = compare[pW];
if (wild == '*')
{
pW++;
if (pW == lW)
return true;
pWm = pW;
pSm = pS + 1;
}
else if (wild == '?' || wild == str[pS])
{
pW++;
pS++;
}
else
{
pW = pWm;
pS = pSm;
pSm++;
}
}
while (pW < lW && compare[pW] == '*')
pW++;
return pW == lW && pS == lS;
}
}
|
|
|
|

|
Hi Erwin,
Thanks for your posting. It did make me decide to investigate the situation.
I still really think this is a situation that begs for recursion. But maybe you were right that substring is not a good idea. So I made this version:
public class MString2
{
public static bool CompareWWc(string strA, string strB, bool ignoreCase)
{
if (ignoreCase)
return CompareWWc(strA.ToLower(), 0, strB.ToLower(), 0);
else
return CompareWWc(strA, 0, strB, 0);
}
public static bool CompareWWc(string strA, string strB)
{
return CompareWWc(strA, 0, strB, 0);
}
private static bool CompareWWc(string strA, int indexA, string strB, int indexB)
{
for (int i = 0; indexA + i < strA.Length; i++)
{
if (strA[indexA + i] == '*')
{
if (indexA + i == strA.Length - 1)
return true;
for (int j = indexB + i; j < strB.Length; j++)
if (CompareWWc(strA, indexA + i + 1, strB, j))
return true;
return false;
}
if (indexB + i >= strB.Length || (strA[indexA + i] != strB[indexB + i] && strA[indexA + i] != '?'))
return false;
}
return strA.Length - indexA == strB.Length - indexB;
}
}
Then I ran some timing tests, using System.Diagnostics.Stopwatch. I put my test case with 19 calls to the function in a loop and executed it 10,000 times. I did this for my original version, your version, and my new version. I compiled the programs in Release mode.
Assuming I haven't made a mistake somewhere, here are my results for a single function call:
My original version: 342 nonoseconds
Your version: 237 nanoseconds
My second version: 279 nanoseconds
Now to tell you the truth, I find it very difficult to get excited about saving 100 nanoseconds at the expense of having two and a half times as many lines of code. Especially since my expected use of this function in my application will probably never exceed a couple hundred calls per day.
Anyway, thanks for getting me to think things over again and make the tests. Personally, at least in this particular case, I prefer programmer understandability to execution efficiency. I've decided to stick with my original version, since I think my second version is more difficult to understand, and the improved efficiency not worth that disadvantage.
|
|
|
|

|
Hi Erwin,
Sorry - my previous numbers are not correct. I was running the programs under the Visual Studio debugger, and that was apparently not good for timing tests.
Here's what I get now:
My original version: 243 nonoseconds
Your version: 76 nanoseconds
My second version: 111 nanoseconds
Assuming these timings are valid, your version is three times faster than my original version, and that is pretty significant, at least in a situation were the function may be used millions times a day.
Sorry for the incorrect timings in my previous posting.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
Matches a string against a wildcard string such as "*.*" or "bl?h.*" etc. This is good for file globbing or to match hostmasks.
| Type | Article |
| Licence | |
| First Posted | 1 May 2001 |
| Views | 683,650 |
| Bookmarked | 89 times |
|
|