and we're good. tests passing and everything
This commit is contained in:
80
README.md
Normal file
80
README.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# wildstring
|
||||
|
||||
Simple String Wildcard Handling
|
||||
|
||||
[](http://travis-ci.org/deltreey/wildstring)
|
||||
|
||||
## Shake it shake it
|
||||
|
||||
Installing wildstring is a snap. wildstring has no dependencies, so you don't need anything else to run it. If you want to use tools though, here's some tips on how to install it with popular installers.
|
||||
|
||||
#### node.js
|
||||
``` bash
|
||||
npm install wildstring
|
||||
```
|
||||
then:
|
||||
``` js
|
||||
var wildstring = require('wildstring');
|
||||
```
|
||||
|
||||
#### bower
|
||||
``` bash
|
||||
bower install wildstring
|
||||
```
|
||||
|
||||
#### html
|
||||
|
||||
make sure you rename the `index.js` file to `wildstring.js` when you add it to your project
|
||||
``` html
|
||||
<script src="wildstring.js"></script>
|
||||
```
|
||||
|
||||
## Hold me tight
|
||||
|
||||
Especially with something that does something new, it's important to see how it works. Below are some examples, but here's a brief explanation as well.
|
||||
|
||||
In this explanation, I'll use `*` as my wildcard for simplicity. If you put a wildcard at the beginning, for example `*Thing` then you can match anything or nothing before your string. So your string could be `Wild Thing` or just `Thing` and it would match fine. The same is true for the end. `Wild*` would match `Wild Thing` or just `Wild`. If you want to match text in the middle of the string, it works the same way. `Wild*Thing` matches both `WildThing` and `Wild and crazy Thing`.
|
||||
``` js
|
||||
wildstring.match('Test*', 'Testing'); // true, wildcard matches 'ing'
|
||||
wildstring.match('*ing', 'testing'); // true, wildcard matches 'test'
|
||||
wildstring.match('Test*', 'Test'); // true, wildcard can match empty strings
|
||||
wildstring.match('*ing', 'Testing it'); // false, no wildcard do match ' it'
|
||||
wildstring.match('Test', 'Testing'); // false, no wildcard to match 'ing'
|
||||
wildstring.match('Test*ing', 'Testing this thing'); // true, matches 'Test' and the end of 'thing', the rest is wildcard matched
|
||||
wildstring.match('*))))))*', ')))))'); // false, not enough parenthesis
|
||||
```
|
||||
|
||||
### You make my heart sing
|
||||
|
||||
You can use wildstring for string interpolation, which makes for an easier interface to parse data from users who maybe don't know regular expressions.
|
||||
``` js
|
||||
wildstring.replace('I * node.*', [ 'love', 'js' ]); // 'I love node.js'
|
||||
wildstring.replace('I * node.*', 'script'); // 'I script node.script' * this behavior is the same as "I * node.*".replace("*", "script") and actually uses that method
|
||||
wildstring.replace('I * node.*', [ 'love' ]); // THROMS AN ERROR, wildcard count and number of strings to insert must match
|
||||
wildstring.replace('*/*/*', [ new Date.getMonth() + 1, new Date.getDate(), new Date.getFullYear]);
|
||||
// 7/15/2015 (or whatever day it is), probably better to learn the js date parser though
|
||||
```
|
||||
|
||||
### You make everything, groovy
|
||||
|
||||
You can use your wildcards with wildstring, so you can wildstring everything. You can even turn off case sensitive matching if you want.
|
||||
``` js
|
||||
wildstring.wildcard = 'stuff';
|
||||
wildstring.match('Test stuff', 'Test wild'); // true, wildcard 'stuff' matches 'wild'
|
||||
wildstring.replace('stuff stuff', [ 'WILD', 'thing' ]); // 'WILD thing'
|
||||
// turn off case sensitive matching
|
||||
wildstring.caseSensitive = false;
|
||||
wildstring.match('tEsT', 'TeSt'); // true, 'test' matches 'test'
|
||||
```
|
||||
|
||||
## I think I love you
|
||||
|
||||
If you want to contribute to wildstring, it's really easy. Just make sure you have [nodejs](https://nodejs.org/) installed and do the following.
|
||||
``` bash
|
||||
git clone https://github.com/deltreey/wildstring
|
||||
# npm install -g grunt-cli # if you don't have it
|
||||
npm install
|
||||
grunt
|
||||
```
|
||||
|
||||
grunt will run all the tests and jshint, so just make sure it passes before submitting a pull request
|
||||
147
index.js
Normal file
147
index.js
Normal file
@@ -0,0 +1,147 @@
|
||||
'use strict';
|
||||
|
||||
var wildstring = {
|
||||
wildcard: '*',
|
||||
caseSensitive: true
|
||||
};
|
||||
|
||||
function checkRollbackStrings (rollbackStrings, patternSubstrings) {
|
||||
for (var s = 0; s < rollbackStrings.length; ++s) {
|
||||
var currentString = rollbackStrings[s].string; // starting with the rolled back string
|
||||
var patternIndex = rollbackStrings[s].index;
|
||||
|
||||
while (patternIndex < patternSubstrings.length) {
|
||||
if (currentString.indexOf(patternSubstrings[patternIndex]) === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
var testString = currentString.substr(1); //remove just one char to retest
|
||||
rollbackStrings.push({ string: testString, index: patternIndex });
|
||||
if (testString.indexOf(patternSubstrings[patternIndex]) === -1) {
|
||||
rollbackStrings.pop();
|
||||
break;
|
||||
}
|
||||
|
||||
currentString = currentString.substr(
|
||||
currentString.indexOf(patternSubstrings[patternIndex]) + patternSubstrings[patternIndex].length
|
||||
);
|
||||
|
||||
patternIndex++;
|
||||
while (patternSubstrings[patternIndex] === '') {
|
||||
patternIndex++;
|
||||
}
|
||||
|
||||
if (patternIndex >= patternSubstrings.length) {
|
||||
if (patternSubstrings[patternSubstrings.length - 1] !== '' &&
|
||||
currentString.length > 0) {
|
||||
// not ending with a wildcard, we need to backtrack
|
||||
break;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wildstring.match = function (pattern, string) {
|
||||
// if there are no wildcards, must be exact
|
||||
if (pattern.indexOf(wildstring.wildcard) === -1) {
|
||||
return pattern === string;
|
||||
}
|
||||
if (!wildstring.caseSensitive) {
|
||||
pattern = pattern.toLowerCase();
|
||||
string = string.toLowerCase();
|
||||
}
|
||||
var patternSubstrings = pattern.split(wildstring.wildcard);
|
||||
|
||||
var patternIndex = 0;
|
||||
var currentString = string;
|
||||
|
||||
// find pattern beginning
|
||||
while (patternSubstrings[patternIndex] === '') {
|
||||
patternIndex++;
|
||||
// if the pattern is just wildcards, it matches
|
||||
if (patternIndex === pattern.length) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (patternIndex === 0 && string.indexOf(patternSubstrings[0]) !== 0) {
|
||||
// not starting with a wildcard
|
||||
return false;
|
||||
}
|
||||
|
||||
var rollbackStrings = [];
|
||||
|
||||
while (patternIndex < patternSubstrings.length) {
|
||||
if (currentString.indexOf(patternSubstrings[patternIndex]) === -1) {
|
||||
return checkRollbackStrings(rollbackStrings, patternSubstrings);
|
||||
}
|
||||
|
||||
// create a queue of strings to roll back and try again if we fail later
|
||||
var testString = currentString.substr(1); //remove just one char to retest
|
||||
rollbackStrings.push({ string: testString, index: patternIndex });
|
||||
if (testString.indexOf(patternSubstrings[patternIndex]) === -1) {
|
||||
rollbackStrings.pop();
|
||||
}
|
||||
|
||||
currentString = currentString.substr(
|
||||
currentString.indexOf(patternSubstrings[patternIndex]) + patternSubstrings[patternIndex].length
|
||||
);
|
||||
|
||||
patternIndex++;
|
||||
while (patternSubstrings[patternIndex] === '') {
|
||||
patternIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (patternIndex >= patternSubstrings.length &&
|
||||
patternSubstrings[patternSubstrings.length - 1] !== '' &&
|
||||
currentString.length > 0) {
|
||||
// not ending with a wildcard, we need to backtrack
|
||||
if (currentString === string) { // this string doesn't even match a little
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkRollbackStrings(rollbackStrings, patternSubstrings);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
wildstring.replace = function (pattern, strings) {
|
||||
if (pattern === undefined || strings === undefined) {
|
||||
throw new Error('wildstring.replace takes the pattern as one parameter and either a string or an array of strings as the second. You didn\'t pass enough parameters.');
|
||||
}
|
||||
if (typeof(strings) === typeof('')) {
|
||||
return pattern.replace(wildstring.wildcard, strings);
|
||||
}
|
||||
if (!Array.isArray(strings) || typeof(pattern) !== typeof('')) {
|
||||
throw new Error('wildstring.replace takes the pattern as one parameter and either a string or an array of strings as the second. Your parameter types are incorrect.');
|
||||
}
|
||||
if (pattern.indexOf(wildstring.wildcard) === -1) {
|
||||
return pattern; // if there are no wildcards, just return the pattern
|
||||
}
|
||||
var patternSubstrings = pattern.split(wildstring.wildcard);
|
||||
if (patternSubstrings.length - 1 !== strings.length) {
|
||||
var message = 'There are a different number of wildcards than strings to replace them. You have ' +
|
||||
wildstring.wildcard +' wildcards in "' + wildstring.wildcard + '" and ' + wildstring.wildcard +
|
||||
' replacement strings.';
|
||||
throw new Error(wildstring.replace(message, [ patternSubstrings.length - 1, pattern, strings.length ]));
|
||||
}
|
||||
|
||||
var result = '';
|
||||
|
||||
for (var s = 0; s < strings.length; ++s) {
|
||||
result += patternSubstrings[s] + strings[s];
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
if (module) { module.exports = wildstring; }
|
||||
310
test/test.js
Normal file
310
test/test.js
Normal file
@@ -0,0 +1,310 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert'),
|
||||
wildstring = require('../');
|
||||
|
||||
describe('wildstring', function() {
|
||||
it('should create an object and set a default wildcard', function() {
|
||||
assert.equal(wildstring.wildcard, '*');
|
||||
});
|
||||
|
||||
describe('#match', function() {
|
||||
it('should match exactly when no wildcard is given', function() {
|
||||
// Given: a string and a pattern that match
|
||||
var pattern = 'test',
|
||||
string = 'test';
|
||||
|
||||
// When: we call wildcard.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should return false if the string doesn\'t match the pattern and no wildcard is given', function() {
|
||||
// Given: a string and a pattern that don't match
|
||||
var pattern = 'test',
|
||||
string = 'testing';
|
||||
|
||||
// When: we call wildcard.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they don't match
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
it('should return false if the string doesn\'t match the pattern and no wildcard is given, even when shorter', function() {
|
||||
// Given: a string and a pattern that don't match
|
||||
var pattern = 'testing',
|
||||
string = '';
|
||||
|
||||
// When: we call wildcard.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they don't match
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
it('should match everything if the pattern is only wildcards', function() {
|
||||
// Given: any string and a pattern that is only wildcards
|
||||
var pattern = '***',
|
||||
string = 'test';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should match longer strings if the pattern ends with a wildcard', function() {
|
||||
// Given: a string that is longer than the pattern, but matches up to the wildcard, and the pattern
|
||||
var pattern = 'test*',
|
||||
string = 'testing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should match longer strings if the pattern begins with a wildcard', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = '*ing',
|
||||
string = 'testing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should match longer strings if the pattern begins with multiple wildcards', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = '***ing',
|
||||
string = 'testing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should match matching strings even if the pattern ends with a wildcard', function() {
|
||||
// Given: a string that is longer than the pattern, but matches up to the wildcard, and the pattern
|
||||
var pattern = 'test*',
|
||||
string = 'test';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should match matching strings even if the pattern ends with multiple wildcards', function() {
|
||||
// Given: a string that is longer than the pattern, but matches up to the wildcard, and the pattern
|
||||
var pattern = 'test***',
|
||||
string = 'test';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should match matching strings even if the pattern begins with a wildcard', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = '*ing',
|
||||
string = 'testing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should not match strings that have extra characters at the end when the pattern doesn\'t end with a wildcard', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = '*ing',
|
||||
string = 'ings';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
it('should not match strings that have extra characters at the beginning when the pattern doesn\'t begin with a wildcard', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = 'ing*',
|
||||
string = 'testing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
it('should match strings that match the beginning and end with a wildcard in the middle', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = 'bow*ing',
|
||||
string = 'bowstring';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should match matching strings even if there\'s a wildcard in the middle', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = 'test*ing',
|
||||
string = 'testing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should work with multiple wildcards in the middle', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = 'te*st*ing',
|
||||
string = 'tea string';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should work with multiple wildcards in the middle and at the beginning', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = '*test*ing',
|
||||
string = 'I\'m testing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should work with multiple wildcards in the middle and at the end', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = 'te*st*ing*',
|
||||
string = 'tea stings';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should move on if a wildcard doesn\'t continue to match but can later', function() {
|
||||
// Given: a string that has a pattern after the wildcard twice
|
||||
var pattern = '*test*ing',
|
||||
string = 'I\'m testing this thing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should handle wildcarding duplicate characters well', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = '*||test*',
|
||||
string = '|||||testing';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
|
||||
it('should fail correctly with duplicate characters', function() {
|
||||
// Given: a string that is longer than the pattern, but matches after to the wildcard, and the pattern
|
||||
var pattern = '*))))))*',
|
||||
string = ')))))';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, false);
|
||||
});
|
||||
|
||||
it('should work with case sensitivity off', function() {
|
||||
// Given: a string that does not match the case of the pattern, and case sensitivity is off
|
||||
wildstring.caseSensitive = false;
|
||||
var pattern = '*TEST',
|
||||
string = 'TeSt';
|
||||
|
||||
// When: we call wildstring.match
|
||||
var result = wildstring.match(pattern, string);
|
||||
|
||||
// Then: we should see that they match
|
||||
assert.equal(result, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#replace', function() {
|
||||
it('sholud return the pattern when no wildcard is given', function() {
|
||||
// Given: a string array and a pattern with no wildcards
|
||||
var pattern = 'test',
|
||||
strings = ['testing'];
|
||||
|
||||
// When: we call wildstring.replace
|
||||
var result = wildstring.replace(pattern, strings);
|
||||
|
||||
// Then: we should see that the pattern is unchanged
|
||||
assert.equal(result, pattern);
|
||||
});
|
||||
|
||||
it('should do ok as a date parser', function() {
|
||||
var date = new Date(2015, 6, 15); // month is 0 based for some reason
|
||||
var strings = [ date.getMonth() + 1, date.getDate(), date.getFullYear() ];
|
||||
var pattern = '*/*/*';
|
||||
var result = wildstring.replace(pattern, strings);
|
||||
|
||||
assert.equal(result, '7/15/2015');
|
||||
});
|
||||
|
||||
it('should tell you when you add too many strings', function() {
|
||||
// Given: more strings than wildcards in the pattern
|
||||
var pattern = 'Test *',
|
||||
strings = [ 'testing', 'strings' ];
|
||||
|
||||
// When: we call wildstring.replace with the pattern and strings
|
||||
assert.throws(function() { wildstring.replace(pattern, strings); });
|
||||
|
||||
// Then: we should get an error
|
||||
});
|
||||
|
||||
it('should tell you when you add too many wildcards', function() {
|
||||
// Given: more strings than wildcards in the pattern
|
||||
var pattern = '* Te*st *',
|
||||
strings = [ 'testing', 'strings' ];
|
||||
|
||||
// When: we call wildstring.replace with the pattern and strings
|
||||
assert.throws(function() { wildstring.replace(pattern, strings); });
|
||||
|
||||
// Then: we should get an error
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user