Convert Human Readable Number Range To Regex
Solution 1:
Validating a number is in a range of numbers with regex is tricky problem. These regexs will match a number within a given range:
\b[0-9]{1,7}\b # 0-9999999
\b[1-9][0-9]{2,6}\b # 100-9999999
\b([4-9][0-9]{4}|[1-9][0-9]{5,6})\b # 40000-9999999
It starts to get out of hand when you have complex ranges
\b(?:5(?:4(?:3(?:2[1-9]|[3-9][0-9])|[4-9][0-9]{2})|[5-9][0-9]{3})|[6-9][0-9]{4}|[1-9][0-9]{5}|[1-8][0-9]{6}|9(?:[0-7][0-9]{5}|8(?:[0-6][0-9]{4}|7(?:[0-5][0-9]{3}|6(?:[0-4][0-9]{2}|5(?:[0-3][0-9]|4[0-3]))))))\b # 54321-9876543
Solution 2:
Forward
3 years later I rediscovered this question, and had some time to solve the puzzle. I'm not entirely clear on why you'd want to use a regex, but I'm sure it has to do with improving database return performance by not forcing all possible results to the client where they'll be evaluated.
That said, I'm sure you have your reasons.
Explanation
This set of functions will construct a regular expression that will do the following:
- validate a given number is between a given range of positive integer numbers
- rejects numbers that are outside that range
- requires the entire string to be numbers
- works with any size numbers
- allow the entire range to include the lower and upper numbers
General overview
The function funRegexRange
does all the heavy lifting. By building a string that will match all numbers from 0
to UpperRange
The function funBuildRegexForRange
then constructs the actual regex with a negative lookahead and a positive lookahead.
The resulting regex will then validate your number is between 0
and the UpperRange
inclusive, and not between 0
and the LowerRange
not inclusive.
The functions will allow either numbers or strings values, but does not validate the inputs are integers. Providing values which do not equate to integers will yield unpredictable results.
Examples
To get the regex for a range from 400 to 500:
re = funBuildRegexForRange( 400, 500, true )
By setting the last parameter to true you it'll show the various parts being constructed and the full regex.
[0-3][0-9]{2}, [0-9]{1,2}
[0-4][0-9]{2}, 500, [0-9]{1,2}
Full Regex = /^(?!(?:[0-3][0-9]{2}|[0-9]{1,2})$)(?=(?:[0-4][0-9]{2}|500|[0-9]{1,2})$)/
The resulting regex looks like
Asking for a range between 400 - 999999999999 [twelve digits] returns this monster:
Full Regex = /^(?!(?:[0-3][0-9]{2}|[0-9]{1,2})$)(?=(?:[0-8][0-9]{11}|9[0-8][0-9]{10}|99[0-8][0-9]{9}|999[0-8][0-9]{8}|9999[0-8][0-9]{7}|99999[0-8][0-9]{6}|999999[0-8][0-9]{5}|9999999[0-8][0-9]{4}|99999999[0-8][0-9]{3}|999999999[0-8][0-9]{2}|9999999999[0-8][0-9]|99999999999[0-8]|999999999999|[0-9]{1,11})$)/
Javascript Code
Live Example: https://repl.it/CLd4/4
Full code:
functionfunRegexRange (UpperRange, Inclusive, Debug) {
// this function will build a basic regex that will match a range of integers from 0 to UpperRangeUpperRange += ""// convert the value to a stringvarArrUpperRange = UpperRange.split("")
var intLength = ArrUpperRange.lengthvarLastNumber = ArrUpperRange[intLength]
varAllSubParts = []
varSubPortion = ""for (i = 0; i < intLength; i++) {
Position = intLength - (i +1)
if ( Position >= 2 ) {
Trailing = "[0-9]{" + Position + "}";
} elseif ( Position == 1 ) {
Trailing = "[0-9]";
} else {
Trailing = "";
}
if ( ArrUpperRange[i] >= 2 ) {
ThisRange = "[0-" + (ArrUpperRange[i] - 1) + "]"
} elseif ( ArrUpperRange[i] == 1 ) {
ThisRange = "0"
} else {
ThisRange = ""
}
if ( Debug ) {
// console.log( "Pos='" + Position + "' i='" + i + "' char='" + ArrUpperRange[i] + "' ThisRange='" + ThisRange + "' Trailing='" + Trailing + "'")
}
if ( ThisRange === "" && Trailing !== "" ) {
// no need to return the this as this will be matched by the future SubPortions
} else {
if ( Position === 0 && ThisRange ==="" && Trailing === "") {
} else {
AllSubParts.push( SubPortion + ThisRange + Trailing);
}
}
SubPortion += ArrUpperRange[i]
}
// insert the last number if this it should be included in the rangeif ( Inclusive ) {
AllSubParts.push(UpperRange)
}
// all all numbers that have less digits than the rangeif ( intLength - 1 >= 2 ) {
Trailing = "[0-9]{1," + ( intLength - 1 ) + "}";
} elseif ( intLength - 1 >= 1 ) {
Trailing = "[0-9]";
} else {
Trailing = "";
}
// insert trailing into the output streamif ( Trailing ){
AllSubParts.push( Trailing );
}
if ( Debug ) {
console.log(AllSubParts.join(", "));
}
returnAllSubParts.join("|");
} // end function funRegexRangefunctionfunBuildRegexForRange ( Start, End, Debug ){
varRegex = newRegExp("^(?!(?:" + funRegexRange (LowerRange, false, Debug) + ")$)(?=(?:" + funRegexRange (UpperRange, true, Debug) + ")$)" ,"" )
if ( Debug ) {
console.log("Full Regex = " + Regex + "")
}
returnRegex
}
varDebug = false;
varInclusive = true;
varLowerRange = "400";
varUpperRange = "500";
// var re = funBuildRegexForRange( LowerRange, UpperRange, true ) if ( Debug ){
for (Range = 0; Range < 13; Range++) {
console.log ("funRegexRange ('" + Range + "', " + Inclusive +") =");
funRegexRange (Range, Inclusive, Debug);
console.log ("");
}
}
varRegex = funBuildRegexForRange( LowerRange, UpperRange, Debug )
for (i = 1000; i < 1020; i++) {
TestNumber = i + ""if ( TestNumber.match(Regex)) {
console.log(TestNumber + " TestNumber='" + TestNumber + "' matches");
} else {
// console.log(TestNumber + " does not match '" + Regex + "'")
}
}
Post a Comment for "Convert Human Readable Number Range To Regex"