Today ended up being busier than expected, but I’m back to things now.
Here’s a basic start, where we attempt to use a regex to capture common parts from the size string.
function getSizeParts(size) {
var sizeRx = /(.*)(small|medium|large|super|s|m|l)(.*)/,
match = sizeRx.exec(size.toLowerCase()),
parts = {prefix: '', size: '', suffix: ''};
if (match) {
parts.prefix = match[1];
parts.size = match[2];
parts.suffix = match[3];
}
return parts;
}
function valueOfSize(size) {
var parts = getSizeParts(size),
size = 0;
// magic happens here
// ...
size = parts.size;
return size; // need to instead return numeric value of size
}
var sizesToTest = ['XS', 'XSmall', 'X small', 'x-small', 'x-s', 'medium', 'm', 'large', 'l', 'xl', 'xxl', 'super', 'superdog', 'super dog 1', 'superdog2'],
i,
size, value;
for (i = 0; i < sizesToTest.length; i += 1) {
size = sizesToTest[i];
value = valueOfSize(size);
console.log('size: ', size, ', value: ', value);
}
Which mostly works, except for situations such as this:
size: X small, value: l
The reason why it’s showing the wrong size is due to regular expressions being greedy by default. The first (.*) capture group grabs the whole string, but the next capture group then has nothing, so the regex removes one character from the first capture group and looks for a match from the second capture group, which it finds with the ‘l’ character from the end of the word “small”.
That’s not how we want the regex to work. Instead of the regex being greedy, we want the first capture group to be lazy instead. We can do that by adding a question mark after the asterisk, so that we instead end up with (.*?)
var sizeRx = /(.*?)(small|medium|large|super|s|m|l)(.*)/,
Now we end up getting the right size for each test.
From here it’s just a matter of turning the size in to a numeric number for ordering, and of dealing with special situations.
We can use a simple switch statement to provide different size values:
function valueOfSize(size) {
var parts = sizeParts(size),
size = -1;
switch (parts.size) {
case 'small':
// fall through
case 's':
size = 1;
break;
case 'medium':
// fall through
case 'm':
size = 2;
break;
case 'large':
// fall through
case 'l':
size = 3;
break;
case 'super':
size = 6;
break;
default:
// leave size at default value
}
return size;
}
Now we just need the prefix to affect the small and large ones, and the suffix to affect the super ones.
Which is done with:
var parts = sizeParts(size),
prefixMatch = parts.prefix.match(/x/g),
numOfXs = prefixMatch && prefixMatch.length || 0,
suffixNumber = parseInt(parts.suffix.match(/\\d/), 10) || 0,
size = -1;
...
case 's':
size = 1 - Math.min(numOfXs, 1); // no more than one X for small
...
case 'l':
size = 3 + Math.min(numOfXs, 2); // no more than two X's for large
...
case 'super':
size = 6 + suffixNumber;
Which results in the following final code for working out the size of different sizing strings:
function sizeParts(size) {
var sizeRx = /(.*?)(small|medium|large|super|s|m|l)(.*)/,
match = sizeRx.exec(size.toLowerCase()),
parts = {
prefix: '',
size: '',
suffix: ''
};
if (match) {
parts.prefix = match[1];
parts.size = match[2];
parts.suffix = match[3];
}
return parts;
}
function valueOfSize(size) {
var parts = sizeParts(size),
prefixMatch = parts.prefix.match(/x/g),
numOfXs = prefixMatch && prefixMatch.length || 0,
suffixNumber = parseInt(parts.suffix.match(/\\d/), 10) || 0,
size = -1;
switch (parts.size) {
case 'small':
// fall through
case 's':
size = 1 - Math.min(numOfXs, 1); // no more than one X for small
break;
case 'medium':
// fall through
case 'm':
size = 2;
break;
case 'large':
// fall through
case 'l':
size = 3 + Math.min(numOfXs, 2); // no more than two X's for large
break;
case 'super':
size = 6 + suffixNumber;
break;
default:
// leave size at default value
}
return size;
}
var sizesToTest = ['XS', 'XSmall', 'unknown', 'X small', 'x-small', 'x-s', 'small', 'medium', 'm', 'large', 'l', 'xl', 'xxl', 'super', 'superdog', 'super dog 1', 'superdog2'],
i, size, value;
for (i = 0; i < sizesToTest.length; i += 1) {
size = sizesToTest[i];
value = valueOfSize(size);
console.log('size: ', size, ', value: ', value);
}
The test code results in the following output:
size: XS , value: 0
size: XSmall , value: 0
size: unknown , value: -1
size: X small , value: 0
size: x-small , value: 0
size: x-s , value: 0
size: small , value: 1
size: medium , value: 2
size: m , value: 2
size: large , value: 3
size: l , value: 3
size: xl , value: 4
size: xxl , value: 5
size: super , value: 6
size: superdog , value: 6
size: super dog 1 , value: 7
size: superdog2 , value: 8