简体   繁体   English

将人类可读的数字范围转换为正则表达式

[英]Convert human readable number range to Regex

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 . 我正在对某些术语进行某种转换,例如,如果用户键入NULL或NOT NULL,则将其转换为regex ^ $或。

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. 我想要的是用户能够输入“ x to y”之类的值并将其转换为正则表达式。 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. 假设尚不存在函数,则假设仅搜索正整数,并说最多7位数字。 so 0 - 9,999,999 can be searched. 因此可以搜索0-9,999,999。 Also the only way this is triggered is by the keyword to with spaces " to ". 同样,触发此方法的唯一方法是使用关键字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. 这适用于数字0-9,但对此进行扩展似乎很难看。 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. 3年后,我重新发现了这个问题,并花了一些时间解决这个难题。 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. 函数funRegexRange完成所有繁重的工作。 By building a string that will match all numbers from 0 to UpperRange 通过构建将匹配从0UpperRange所有数字的字符串

The function funBuildRegexForRange then constructs the actual regex with a negative lookahead and a positive lookahead. 然后,函数funBuildRegexForRange构造具有负先行和正先行的实际正则表达式。

The resulting regex will then validate your number is between 0 and the UpperRange inclusive, and not between 0 and the LowerRange not inclusive. 然后,生成的正则表达式将验证您的数字是否介于0UpperRange之间(包括UpperRange ,而不是介于0LowerRange之间(不包括LowerRange

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: 要获取介于400到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. 通过将最后一个参数设置为true,将显示正在构造的各个部分以及完整的正则表达式。

[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: 要求范围在400-999999999999 [十二个数字]之间,则会返回此怪物:

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 JavaScript代码

Live Example: https://repl.it/CLd4/4 实时示例: 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 + "'")
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM