balanced-match
Advanced tools
Comparing version
70
index.js
module.exports = balanced; | ||
function balanced(a, b, str) { | ||
var bal = 0; | ||
var m = {}; | ||
var ended = false; | ||
var r = range(a, b, str); | ||
for (var i = 0; i < str.length; i++) { | ||
if (a == str.substr(i, a.length)) { | ||
if (!('start' in m)) m.start = i; | ||
bal++; | ||
} | ||
else if (b == str.substr(i, b.length) && 'start' in m) { | ||
ended = true; | ||
bal--; | ||
if (!bal) { | ||
m.end = i; | ||
m.pre = str.substr(0, m.start); | ||
m.body = (m.end - m.start > 1) | ||
? str.substring(m.start + a.length, m.end) | ||
: ''; | ||
m.post = str.slice(m.end + b.length); | ||
return m; | ||
return r && { | ||
start: r[0], | ||
end: r[1], | ||
pre: str.slice(0, r[0]), | ||
body: str.slice(r[0] + a.length, r[1]), | ||
post: str.slice(r[1] + b.length) | ||
}; | ||
} | ||
balanced.range = range; | ||
function range(a, b, str) { | ||
var begs, beg, left, right, result; | ||
var ai = str.indexOf(a); | ||
var bi = str.indexOf(b, ai + 1); | ||
var i = ai; | ||
if (ai >= 0 && bi > 0) { | ||
begs = []; | ||
left = str.length; | ||
while (i < str.length && i >= 0 && ! result) { | ||
if (i == ai) { | ||
begs.push(i); | ||
ai = str.indexOf(a, i + 1); | ||
} else if (begs.length == 1) { | ||
result = [ begs.pop(), bi ]; | ||
} else { | ||
beg = begs.pop(); | ||
if (beg < left) { | ||
left = beg; | ||
right = bi; | ||
} | ||
bi = str.indexOf(b, i + 1); | ||
} | ||
i = ai < bi && ai >= 0 ? ai : bi; | ||
} | ||
} | ||
// if we opened more than we closed, find the one we closed | ||
if (bal && ended) { | ||
var start = m.start + a.length; | ||
m = balanced(a, b, str.substr(start)); | ||
if (m) { | ||
m.start += start; | ||
m.end += start; | ||
m.pre = str.slice(0, start) + m.pre; | ||
if (begs.length) { | ||
result = [ left, right ]; | ||
} | ||
return m; | ||
} | ||
return result; | ||
} |
{ | ||
"name": "balanced-match", | ||
"description": "Match balanced character pairs, like \"{\" and \"}\"", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"repository": { | ||
@@ -16,3 +16,3 @@ "type": "git", | ||
"devDependencies": { | ||
"tape": "~1.1.1" | ||
"tape": "~4.2.2" | ||
}, | ||
@@ -19,0 +19,0 @@ "keywords": [ |
@@ -50,2 +50,11 @@ # balanced-match | ||
### var r = balanced.range(a, b, str) | ||
For the first non-nested matching pair of `a` and `b` in `str`, return an | ||
array with indexes: `[ <a index>, <b index> ]`. | ||
If there's no match, `undefined` will be returned. | ||
If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `[ 1, 3 ]`. | ||
## Installation | ||
@@ -52,0 +61,0 @@ |
@@ -55,3 +55,31 @@ var test = require('tape'); | ||
}); | ||
t.deepEqual(balanced('{{', '}}', 'pre{{{in}}}post'), { | ||
start: 3, | ||
end: 9, | ||
pre: 'pre', | ||
body: '{in}', | ||
post: 'post' | ||
}); | ||
t.deepEqual(balanced('{{{', '}}', 'pre{{{in}}}post'), { | ||
start: 3, | ||
end: 8, | ||
pre: 'pre', | ||
body: 'in', | ||
post: '}post' | ||
}); | ||
t.deepEqual(balanced('{', '}', 'pre{{first}in{second}post'), { | ||
start: 4, | ||
end: 10, | ||
pre: 'pre{', | ||
body: 'first', | ||
post: 'in{second}post' | ||
}); | ||
t.deepEqual(balanced('<?', '?>', 'pre<?>post'), { | ||
start: 3, | ||
end: 4, | ||
pre: 'pre', | ||
body: '', | ||
post: 'post' | ||
}); | ||
t.end(); | ||
}); |
8250
14.3%128
36.17%90
11.11%