D5145c421cd25af6fa577c15219add90

I want to have a string which is can be searched by another string which contains * wildcards. I was having trouble, so I made a simple test framework to help me get it working. I've included the tests so that any refactorings can be checked.

Edit: I've found the problems that meant it didn't run and fixed them so it should be fine now. I've also added the extra test cases suggested below.

function matches(matchString,list)
{
  goodSoFar = false;
  parts = matchString.split('*');
  for (i = 0; i < list.length; i++)
  {
    for (j = 0; j < parts.length; j++)
    {
      if (list[i].indexOf(parts[j]) > -1)
      {
        if (parts[j] != '')
        {
          list[i] = list[i].split(parts[j]);
          list[i][0] = '';
          list[i] = list[i].join();
        }
        goodSoFar = true;
      }
      else
      {
        goodSoFar = false;
        break;
      }
    }
    if (goodSoFar)
      return true;
  }
  return false;
}
function generateList()
{
	list = new Array("The quick brown fox jumps over the lazy dog","All work and no play makes Jack a dull boy","qwerty");
	return list;
}

fails = new Array();

testList = generateList();
if (!matches(testList[0],testList))
  fails.push("Simple string match - should be true");

testList = generateList();
if (matches("Non-matching string",testList))
  fails.push("Simple non-matching string - should be false");

testList = generateList();
if (!matches('*',testList))
  fails.push("Asterisk - should be true");

testList = generateList();
if (!matches('All work*',testList))
  fails.push("Part string then asterisk - should be true");

testList = generateList();
if (!matches('The quick*',testList))
  fails.push("The quick then asterisk - should be true");

testList = generateList();
if (matches('no match*',testList))
  fails.push("Non-matching with * - should be false");

testList = generateList();
if (!matches(testList[1],testList))
  fails.push("Simple string match 2 - should be true");

testList = generateList();
if (!matches('*lazy dog',testList))
  fails.push("Asterisk then part string - should be true");

testList = generateList();
if (matches('*no match',testList))
  fails.push("Asterisk then non-matching string - should be false");

testList = generateList();
if (!matches('The quick*lazy dog',testList))
  fails.push("Match with asterisk in middle - should be true");

testList = generateList();
if (matches('The quick*no match',testList))
  fails.push("Part match with asterisk in middle - should be false");

testList = generateList();
if (!matches('The quick*jumps over*lazy dog',testList))
  fails.push("Match with two asterisks in middle - should be true");

testList = generateList();
if (matches('The quick*wrong*lazy dog',testList))
  fails.push("Incorrect match with two asterisks in middle - should be false");

testList = generateList();
if (!matches('*The quick brown fox jumps over the lazy dog',testList))
  fails.push("Asterisk matching '' at the start - should be true");

testList = generateList();
if (!matches('The quick brown fox jumps over the lazy dog*',testList))
  fails.push("Asterisk matching '' at the end - should be true");

testList = generateList();
if (matches('The quick*over*jumps*lazy dog',testList))
  fails.push("Seperate parts match but incorrect order - should be false");
if (fails.length == 0)
  document.write('<div style="width:100%;background-color:green;color:white;text-align:center">All tests pass</div><br />&nbsp;');
else
  document.write('<div style="width:100%;background-color:red;color:white;text-align:center">The following tests have failed:<br /> '
      + fails.join('<br />') + '</div>');

Refactorings

No refactoring yet !

9b4d76224c1fefc34b682e799df98624

dpm1661

March 3, 2010, March 03, 2010 05:57, permalink

No rating. Login to rate!

Hi Nathan,

You're so close to recreating a subset of the syntax for "regular expressions", which are already built in to JavaScript.

Most JS string matching methods can take a regular expression as an argument, and you can also create regular expression objects (RegExp objects), and use the methods of those objects to do similar tests.

Regular expressions allow you to match wildcards very easily (almost too easily?), but the syntax is just slightly different than what you are trying to do here. The regular expression '.*' matches any number of any character.

I couldn't get your original function to work. I kept getting an error on line 11. But, I think you can save yourself the trouble by using regular expressions instead.

I rewrote your function to demonstrate how the usage of regular expressions can cover what you need to do, however, you probably would never use a function like this for real. It will probably make more sense to not use a custom function at all, and instead apply a regular expression wherever needed. But, for completeness, below you'll find your refactored function.

Maybe someone here can recommend a good/free/online tutorial for regular expressions? I can personally vouch for the O'reilly book "Mastering Regular Expressions", http://www.amazon.com/Mastering-Regular-Expressions-Jeffrey-Friedl/dp/1565922573.>

function matches(matchString,list)
{

    // if instead of using '*' to match wildcards, you used '.*', then
    // your matchString would be a valid regular expression. This next
    // command makes that conversion, to demonstrate that regular expressions
    // satisfy your needs.
    matchString = matchString.replace(/\*/g, '.*');

    // Since matchString was passed as an argument, we use the RegExp
    // constructor.  If we were including a regular expression as a literal
    // then we could use the /regex/ shortcut (as above).
    matchStringAsRegex = new RegExp(matchString);

    // loop through the list and apply the RegExp.test() method to each string
    // in the list.  RegExp.test() returns true if the regular expression
    // matches and false otherwise.
    for (i = 0; i < list.length; i++)
    {
        if (matchStringAsRegex.test(list[i]))
        {
            return true;
        }
    }
    return false;

    // note, if you use regular expressions instead of a custom function, you
    // probably won't need a function at all.  This business of converting the
    // matchString to a regular expression syntax, then applying the RegExp
    // constructor is ONLY to demonstrate that this function satisfies your
    // test suite. You'll probably wan't to ditch the function altogether, and
    // use the instant application of regular expressions instead.

}
9b4d76224c1fefc34b682e799df98624

dpm1661

March 3, 2010, March 03, 2010 06:14, permalink

No rating. Login to rate!

Oh, one more thing about the '.*' regular expression. There are some cases not covered in your test suite, and I wanted to include some more tests so you could be sure this does what you want it to do.

The '.*' pattern can be considered somewhat dangerous, since it matches any number of any characters, including ZERO of any character. This means you could stick an asterisk anywhere in an already matching string without any consequences. If this isn't what you want, there are ways around it...

if (!matches('the lazy dog*',testList))
  fails.push("Asterisk matches zero characters also - should be true");

if (!matches('*The quick',testList))
  fails.push("Asterisk matches zero characters also - should be true");

if (!matches('The quick *brown fox',testList))
  fails.push("Asterisk matches zero characters also - should be true");
D5145c421cd25af6fa577c15219add90

Nathan

March 3, 2010, March 03, 2010 06:54, permalink

No rating. Login to rate!

Thanks for that DPM. I had considered using regular expressions, but it's for matching user inputed match strings in a browser extension, so the data will be a string, and it needs to be much simpler so the user doesn't have to escape special characters. As for the error, yes, I'm getting that too... looks like I was a bit hasty in submitting, because I didn't see it before. I'll try and work out what's wrong.

D41d8cd98f00b204e9800998ecf8427e

steenslag

March 3, 2010, March 03, 2010 08:38, permalink

No rating. Login to rate!

"Maybe someone here can recommend a good/free/online tutorial for regular expressions? "
www.rubular.com is great for experimenting with regexps. It uses the ruby regexp engine, but I guess it's useful for any language.

34db50b7ce2e115afadf5a765b950739

Thomas Salvador

March 9, 2010, March 09, 2010 21:05, permalink

No rating. Login to rate!

hi.

imho http://www.regular-expressions.info/tutorial.html
looks good. site is dedicated to regex with in-detail descriptions.

regards,
thomas.

Your refactoring





Format Copy from initial code

or Cancel