I have a table that is displayed using datatables, above each column I have an empty text form field that users can type in terms to filter on. This works fine on all text fields, and works ok on integer fields as well. I am doing some conversion for some terms such as if the user types in NULL or NOT NULL for example I convert that to the regex ^$ or .
I know regex is intended to search text strings but this is what datatables uses so thats why I am doing this. What I want is for users to be able to type in a value such as "x to y" and to be able to convert that to a regular expression. I cannot find a function that does this, if anyone knows of one please let me know.
Assuming a function doesn't already exist, assume that only positive integers will be searched, and say up to 7 digits. so 0 - 9,999,999 can be searched. Also the only way this is triggered is by the keyword to with spaces " to ".
so something like this to start:
function convertNumRangeRegex(s){
if(s.indexOf(" to ") != -1){
var range = s.split(" to ");
lowRange = Number(range[0]);
highRange = Number(range[1]);
if(lowRange >= 0 && lowRange < 10 && highRange < 10){
s = "^[" + lowRange + "-" + highRange + "]$";
}};
return s;
};
This works with numbers 0-9, but expanding on this seems like it would get pretty ugly. I am up for any ides. Thanks.
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
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:
function funRegexRange (UpperRange, Inclusive, Debug) {
// this function will build a basic regex that will match a range of integers from 0 to UpperRange
UpperRange += "" // convert the value to a string
var ArrUpperRange = UpperRange.split("")
var intLength = ArrUpperRange.length
var LastNumber = ArrUpperRange[intLength]
var AllSubParts = []
var SubPortion = ""
for (i = 0; i < intLength; i++) {
Position = intLength - (i +1)
if ( Position >= 2 ) {
Trailing = "[0-9]{" + Position + "}";
} else if ( Position == 1 ) {
Trailing = "[0-9]";
} else {
Trailing = "";
}
if ( ArrUpperRange[i] >= 2 ) {
ThisRange = "[0-" + (ArrUpperRange[i] - 1) + "]"
} else if ( 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 range
if ( Inclusive ) {
AllSubParts.push(UpperRange)
}
// all all numbers that have less digits than the range
if ( intLength - 1 >= 2 ) {
Trailing = "[0-9]{1," + ( intLength - 1 ) + "}";
} else if ( intLength - 1 >= 1 ) {
Trailing = "[0-9]";
} else {
Trailing = "";
}
// insert trailing into the output stream
if ( Trailing ){
AllSubParts.push( Trailing );
}
if ( Debug ) {
console.log(AllSubParts.join(", "));
}
return AllSubParts.join("|");
} // end function funRegexRange
function funBuildRegexForRange ( Start, End, Debug ){
var Regex = new RegExp("^(?!(?:" + funRegexRange (LowerRange, false, Debug) + ")$)(?=(?:" + funRegexRange (UpperRange, true, Debug) + ")$)" ,"" )
if ( Debug ) {
console.log("Full Regex = " + Regex + "")
}
return Regex
}
var Debug = false;
var Inclusive = true;
var LowerRange = "400";
var UpperRange = "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 ("");
}
}
var Regex = 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 + "'")
}
}