Lasse said:
Asen said:
I would like to have function which automatically generates ranges.
For example range 0 - 25 could be written as:
...
toRange(255); //(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9]|0)
toRange(26); //(?:2[0-6]|1[0-9]|[1-9]|0)
Any suggestions or improvements are welcome.
I finally got around to writing the code I had an idea for.
The idea is to make the regexp as fast as possible by making all
alternatives mutually exclusive, so there won't need to be any
backtracking.
It also tries to generate non-stupid regexps (i.e., use '\d' instead
of '[0-9]' and '?' instead of '{0,1}'). That's not perfect yet
[ code elided ]
And I finally got around to writing the one I had in mind. It's
different enough from the previous two solutions to be worth
mentioning.
The idea is to work recursively with ranges that have both a start and
an end, with a tree structure for, say 267 - 4301, of
267-4301
+- 267-999
| +- 267-299
| | +- 267-269: 26[7-9]
| | `- 270-299: 2[7-9]\d
| `- 300-999: [3-9]\d\d
`- 1000-4301
+- 1000-3999: [1-3]\d\d\d
`- 4000-4301
+- 4000-4299: 4[0-2]\d\d
`- 4300-4301: 43[0-1]
to create a partial regex that looks like: "(?:26[7-9]|2[7-9]\d|[3-9]\d
\d|[1-3]\d\d\d|4[0-2]\d\d|430[0-1])"
Mine has very minimal testing, and I would not be surprised to hear
that it's buggy. You can see an example of it at <http://
scott.sauyet.com/Javascript/Test/Range/2011-06-13c/>. The relevant
code is
var toRange = (function() {
function range(vals) {
var parts = vals.split("-"),
start = parts[0], end = parts[1], match;
if (start === end) {
return start;
} else if (start.length < end.length) {
return range(start + "-" + start.replace(/\d/g, "9")) + "|" +
range("1" + start.replace(/\d/g, "0") + "-" + end);
} else if (match = /^(\d*)(\d)(0*)\-\1(\d)9*$/.exec(vals)) {
return match[1] + ((match[2] === "0" && match[4] === "9") ?
"\\d" : ("[" + match[2] + "-" + match[4]) + "]" +
match[3].replace(/0/g, "\\d"));
} else if (match = /^(\d*)(\d)\d*\-\1(\d)9(9*)$/.exec(vals)) {
return range(start + "-" + match[1] + match[2] + "9" +
match[4]) + "|" +
range(match[1] + (1 + Number(match[2])) + "0" +
match[4].replace(/9/g, "0") + "-" + end);
} else if (match = /^(\d*)(\d+)\-\1(\d)(\d*)$/.exec(vals)) {
return range(start + "-" + match[1] + (Number(match[3]) - 1)
+
match[4].replace(/\d/g, "9")) + "|" +
range(match[1] + match[3] + match[4].replace(/\d/g,
"0") +
"-" + end)
} else if (match = /^(\d*)(\d)\-\1(\d)$/.exec(vals)) {
return match[1] + "[" + match[2] + "-" + match[3] + "]";
}
return ""; // throw error?
}
return function(start, end) {
if (arguments.length < 1) {return "";} // throw error?
if (arguments.length == 1) {
return "(?:" + range("0-" + start) + ")";
}
if (start > end) {return "";} // throw error?
return "(?:" + range("" + start + "-" + end) + ")";
};
}());
(This is a little ugly here, as I try to keep the line length down.
The online version is somewhat clearer.)
Here again, the arguments must be non-negative integers, and if two
are supplied, the second must be no smaller than the first.
-- Scott