From 7b95fee1bdef738ffbe742b0cf0b4753254d82ee Mon Sep 17 00:00:00 2001 From: Belema Gancarz Date: Mon, 7 Dec 2015 15:18:50 +0000 Subject: [PATCH] Adds extract function. --- README.markdown | 16 ++++++++++++++ extract.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ index.js | 1 + tests/extract.js | 21 ++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 extract.js create mode 100644 tests/extract.js diff --git a/README.markdown b/README.markdown index dc444939..6b8f4468 100644 --- a/README.markdown +++ b/README.markdown @@ -791,6 +791,22 @@ map("Hello world", function(x) { // => "HellO wOrld" ``` +#### extract(string, string) => array + +Extract tokens from string in requested order. + +```javascript +extract('My name is {0} and I like {1}', 'My name is Sponge Bob and I like square pants'); +// => "['Sponge Bob', 'square pants']" + +extract('{2}, {1}, and {0}', 'Red, White, and Blue'); +// => "['Blue', 'White', 'Red']" + +var f = extract('My name is {0} and I like {1}'); +f('My name is Bob and I like sponges'); +// => "['Bob', 'sponges']" +``` + ### Library functions If you require the full library you can use chaining and aliases diff --git a/extract.js b/extract.js new file mode 100644 index 00000000..29cede72 --- /dev/null +++ b/extract.js @@ -0,0 +1,56 @@ +var escapeRegExp = require('./helper/escapeRegExp'); + +function extractorFor(pattern, size, tokenOrder) { + return function (str) { + var matches = String.prototype.match.call(str || "", new RegExp(pattern)); + if (matches === null) { + return null; + } + + var result = []; + for (var i = 0; i < size; i++) { + result[i] = matches[tokenOrder.indexOf(i) + 1]; + } + + return result; + }; +} + +function extractorFromTemplate(template) { + if (!template || typeof template !== "string") { + return function () { return null; } + } + + var tokens = (template.match(/\{([1-9]\d*)?\d\}/g) || []) + .map(function(token) { return parseInt(token.substring(1, token.length - 1), 10); }) + .reduce(function(array, current) { + if (array.indexOf(current) === -1) { + array.push(current); + } + return array; + }, []); + + var tokenNumber = tokens + .map(function (token) { return token; }) + .sort(function(a, b) { return a - b; }) + .reduce(function (previous, token, index) { + if (previous > index && token !== index) { + return index; + } + return previous; + }, tokens.length); + + template = escapeRegExp(template); + for (var i = 0; i < tokenNumber; i++) { + template = template.replace(escapeRegExp('{' + i + '}'), '(.+)'); + } + + return extractorFor(template, tokenNumber, tokens.filter(function (token) { return token < tokenNumber; })); +} + +module.exports = function extract(template, str) { + if (typeof str === "undefined") { + return extractorFromTemplate(template); + } + return extractorFromTemplate(template)(str); +}; diff --git a/index.js b/index.js index 00e0690f..38bcb97f 100644 --- a/index.js +++ b/index.js @@ -77,6 +77,7 @@ s.exports = require('./exports'); s.escapeRegExp = require('./helper/escapeRegExp'); s.wrap = require('./wrap'); s.map = require('./map'); +s.extract = require('./extract'); // Aliases s.strip = s.trim; diff --git a/tests/extract.js b/tests/extract.js new file mode 100644 index 00000000..679d3f16 --- /dev/null +++ b/tests/extract.js @@ -0,0 +1,21 @@ +var deepEqual = require('assert').deepEqual; +var extract = require('../extract'); + + +test('#extract', function(){ + deepEqual(extract(null, 'My name is Bob and I like sponges'), null); + deepEqual(extract('My name is Bob and I like sponges', null), null); + deepEqual(extract('My name is Bob and I like sponges', 'My name is Bob and I am a builder'), null); + deepEqual(extract('My name is Bob and I like sponges', 'My name is Bob and I like sponges'), []); + deepEqual(extract('My name is {0} and I like sponges', 'My name is Bob and I like sponges'), ['Bob']); + deepEqual(extract('My name is Bob and I like {0}', 'My name is Bob and I like sponges'), ['sponges']); + deepEqual(extract('My name is {0} and I like square pants', 'My name is Sponge Bob and I like square pants'), ['Sponge Bob']); + deepEqual(extract('My name is {1} and I like sponges', 'My name is Bob and I like sponges'), null); + deepEqual(extract('My name is {1} and I like sponges', 'My name is {1} and I like sponges'), []); + deepEqual(extract('My name is {0}Bob and I like sponges', 'My name is Bob and I like sponges'), null); + deepEqual(extract('My name is {0} and I like {1}', 'My name is Bob and I like sponges'), ['Bob', 'sponges']); + deepEqual(extract('My name is {1} and I like {0}', 'My name is Bob and I like sponges'), ['sponges', 'Bob']); + deepEqual(extract('My name is {0} and I like {1}', 'Your name is Bob and you like sponges'), null); + deepEqual(extract('Our names are {0} & {0} and we like {1} & {1}', 'Our names are Bob & {0} and we like sponges & {1}'), ['Bob', 'sponges']); + deepEqual(extract('My name is [B|o|b] and {I}+ like (.+) & {0}', 'My name is [B|o|b] and {I}+ like (.+) & sponges'), ['sponges']); +});