问题 JavaScript RegExp自动格式化Pattern


我已经看到很多函数在stackflow社区中格式化电话或数字(逗号和小数),就像这个问题一样 这里 和别的。这就是我想要的:

第1步:为这样的模式维护库:

var library = {
    fullDate : {
        pattern : /^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/,
        error : "Invalid Date format. Use YYYY-MM-DD format."
    },
    fullDateTime : {
        pattern : /^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}$/,
        error : "Invalid DateTime format. Use YYYY-MM-DD HH:MM (24-hour) format."
    },
    tel : {
        pattern : /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/,
        error : "Invalid Telephone format."
    }
};

第2步:在键入时自动添加字符。例如,添加一个 - 在日期中的4个数字之后。

我有一个文字字段说:

<input type="text" data-validate="fullDate" placeholder="YYYY-MM-DD"/>

以及启动脚本的可能位置:

$('body').on('keyup','input',function(){
   var validate = $(this).data('validate');
   var pattern = library[validate].pattern;


    //Some more steps here....

});

但是,我不能再进一步了,因为我是RegExp的新手。这是一个 启动小提琴。任何人?

进一步说明:我已经能够使用以下函数进行验证,但我想要的是自动生成模式:

function validate(libraryItem, subject){
    var item = library[libraryItem];
    if(item !== undefined){
        var pattern = item.pattern;
        if(validatePattern(pattern, subject)){
            return true;
        } else {
            return item.error;
        }
    }
    return false;
}


function validatePattern(pattern, subject){
    return pattern.test(subject);
}

6104
2018-06-07 21:55


起源

验证的正则表达式很好,但它们不适合提出建议......因为你需要某种状态机。 - Ja͢ck


答案:


它并不像你想象的那么复杂。您正在寻找的是JQuery Masked输入和其他替代库。这里是 文件。所有你需要的是:

 <input id="date" type="text" placeholder="YYYY-MM-DD"/>

和脚本:

 $("#date").mask("9999-99-99",{placeholder:"YYYY-MM-DD"});

这是演示笔链接: http://codepen.io/anon/pen/gpRyBp

要实现验证,请使用此库: https://github.com/RobinHerbots/jquery.inputmask 


6
2018-06-13 04:27



可以处理可变数字的数字吗?我们可以使字符串的一部分可选。它可以确保理智的月份号码,日期号码通过。 - Anurag Peshne
@AnuragPeshne使用 github.com/bseth99/sandbox/blob/master/projects/jquery-ui/... 用于验证。描述在这里找到 bseth99.github.io/projects/jquery-ui/5-jquery-masks.html 和github链接是 github.com/RobinHerbots/jquery.inputmask - Dinesh Devkota


这里需要的是分解子表达式中的正则表达式,该表达式匹配字符串的一部分并根据正则表达式中的下一个字符建议完成。 我写了一个天真的Parser,它解析表达式并分成原子子表达式。

var parser = function(input) {
    var tokenStack = [];
    var suggestions = [];
    var suggestion;
    var lookAhead;

    if (input[0] === '/')
        input = input.slice(1, input.length - 1);

    var i;
    for (i = 0; i < input.length - 1; i++) {
        lookAhead = input[i + 1];
        switch (input[i]) {
        case '(':
            tokenStack.push('(');
            break;
        case '[':
            tokenStack.push('[');
            break;
        case ')':
            if (tokenStack[tokenStack.length - 1] === '(') {
                tokenStack.pop();
                if (tokenStack.length === 0) {
                    suggestion = generateSuggestion(input, i);
                    if (suggestion !== null)
                        suggestions.push(suggestion);
                }
            }
            else
                throw 'bracket mismatch';
            break;
        case ']':
            if (lookAhead === '{') {
                while (input[i] !== '}')
                    i++;
            }
            if (tokenStack[tokenStack.length - 1] === '[') {
                tokenStack.pop();
                if (tokenStack.length === 0) {
                    suggestion = generateSuggestion(input, i);
                    if (suggestion !== null)
                        suggestions.push(suggestion);
                }
            }
            else
                throw 'bracket mismatch';
            break;
        default:
            if (tokenStack.length === 0) {
                suggestion = generateSuggestion(input, i);
                if (suggestion !== null)
                    suggestions.push(suggestion);
            }
            break;
        }
    }
    return suggestions;
}

var generateSuggestion = function(input, index) {
    if (input[index].match(/[a-zA-Z\-\ \.:]/) !== null)
        return {
            'regex': input.slice(0, index) + '$',
            'suggestion': input[index]
        };
    else
        return null;
}

这是样本输入和输出 parser()

parser('/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/');
// output:
[ { regex: '^[0-9]{4}$', suggestion: '-' },
  { regex: '^[0-9]{4}-[0-9]{1,2}$', suggestion: '-' } ]

因此,每一个 keyup 你需要检查生成的RegExp列表 parser 如果其中任何一个与输入匹配,则使用建议。

编辑:

编辑 generateSuggestion 只匹配完整的表达式。 这是小提琴样本: http://jsfiddle.net/a7kkL6xu/6/

忽略退格: http://jsfiddle.net/a7kkL6xu/7/


2
2018-06-08 09:26



我很感激,但尝试输入20170908 - tika
是的,因为正则表达式允许月份有多个数字,所以在输入第一个数字后脚本会给出“ - ”。在这里,我们需要稍微调整一下代码。尝试传球 /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/ 生成建议时解析器。 - Anurag Peshne
@tika:我已经调整过了 generateSuggestion 一点,以便它匹配整个表达式。现在输入像20170908这样的值不会有问题。尝试新的小提琴: jsfiddle.net/a7kkL6xu/6 - Anurag Peshne
@tika是的,您需要根据需要调整事件监听器。我希望您能够清楚地了解和调整实施情况。 - Anurag Peshne
@tika:一个简单的调整就是在没有命中退格时更新文本值。试试这个小提琴: jsfiddle.net/a7kkL6xu/7 - Anurag Peshne


这可以使用单个正则表达式完成。
这要求MM:DD和HH:MM为2位,YYYY为4位数
完全有效的输入,但匹配所有部分。

可以使得允许所提到的2位有效的单个数字有效性。
但这样做,将为时过早 建议 在...上 - - [ ] : 形成。
如果你不想注入建议,那么1或2位数就可以了。

JavaScript不允许使用lookbehind断言,因此部分字段表达式
低于各自组中的有效字段表达式。

基本上输入的是输入 改写 在每个关键的新闻事件。
您所做的就是匹配事件处理程序中的当前输入。

没有建议,你只需用整个匹配(组0)来写入输入。

匹配(组0)仅包含有效的部分或完全匹配。

有效的已完成字段捕获组为1到5
[ 年,月,日,小时,分钟 ]

不完整的字段捕获是第6到第10组
[ 分钟,小时,日,月,年 ]

这是逻辑:

// Note 1 - can handle control chars by just returning.
// Note 2 - can avoid rewrite by keeping a global of last good,
//          then return if current == last.

if ( last char of group 0 is a dash '-' or space ' ' or colon ':' 
     or any of groups 6 - 10 matched
     or group 5 matched )
   set input equal to the group 0 string;  

else if ( group 4 matched )  // Hours
   set input equal to  group 0 string + ':';  

else if ( group 3 matched )  // Day
   set input equal to group 0 string + ' ';  

else if ( group 1 or 2 matched )  // Year or Month
   set input equal to  group 0 string + '-';   

else   // Here, effectively strips bad chars from input box
       // before they are displayed.
   set input equal to  group 0 string;   

请注意,如果一个组不匹配,它的值将是 空值
并检查整个有效性,应该没有部分和
只有YYYY-MM-DD必须完成组1 - 3,或者选择1 - 5组
时间HH:MM

最后的说明: 这是一个解析器,实际上是外观的测试用例,即。闪烁,实时输入重写。
如果进展顺利,处理程序中的逻辑可以包括基于月份的日期验证(和重写)。
此外,前提可以扩展到任何类型的输入,任何类型的形式和
形式分隔符组合等。
如果有效,您可以构建一个库。

 # /^(?:(19\d{2}|20[0-1]\d|202[0-5])(?:-(?:(0[1-9]|1[0-2])(?:-(?:(0[1-9]|[1-2]\d|3[0-1])(?:[ ](?:(0\d|1\d|2[0-3])(?::(?:(0\d|[1-5][0-9])|([0-5]))?)?|([0-2]))?)?|([0-3]))?)?|([01]))?)?|(19\d?|20[0-2]?|[12]))/


 ^                             # BOL 
 (?:
      (                             # (1 start), Year 1900 - 2025
           19 \d{2} 
        |  20 [0-1] \d 
        |  202 [0-5] 
      )                             # (1 end)
      (?:
           -                             # -
           (?:
                (                             # (2 start), Month    00 - 12
                     0 [1-9] 
                  |  1 [0-2] 
                )                             # (2 end)
                (?:
                     -                             # -
                     (?:
                          (                             # (3 start), Day   00 - 31
                               0 [1-9] 
                            |  [1-2] \d 
                            |  3 [0-1] 
                          )                             # (3 end)
                          (?:
                               [ ]                           # space
                               (?:
                                    (                             # (4 start), Hour  00 - 23
                                         0 \d 
                                      |  1 \d 
                                      |  2 [0-3] 
                                    )                             # (4 end)
                                    (?:
                                         :                             # :
                                         (?:
                                              (                             # (5 start), Minutes  00 - 59
                                                   0 \d 
                                                |  [1-5] [0-9]                                             
                                              )                             # (5 end)
                                           |  
                                              ( [0-5] )                     # (6)
                                         )?
                                    )?
                                 |  
                                    ( [0-2] )                     # (7)
                               )?
                          )?
                       |  
                          ( [0-3] )                     # (8)
                     )?
                )?
             |  
                ( [01] )                      # (9)

           )?
      )?
   |  
      (                             # (10 start)
           19 \d? 
        |  
           20 [0-2]? 
        |  
           [12] 
      )                             # (10 end)
 )

2
2018-06-15 01:38





如果此时只有一个可能的选择,则只能添加一个字符。 一个例子是一个正则表达式 YYYY-MM-DD HH24:mm 格式: -: 和  (空间)可以添加。这是相应的正则表达式(/ 省略使其更具可读性,它比问题中的更严格,一些非法日期仍然可能像2月31日那样):

^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01]) (?:[01][0-9]|2[0-3]):[0-5][0-9]$

固定长度 你可以输入 使用@ DineshDevkota的解决方案 添加文字并使用正则表达式验证整个文本。我认为这是最干净,最简单的解决方案。您还可以捕获年,月和日以数学方式验证日期。 “不是将来的日期”或“过去最长100年”这样的规则也只能在JS中进行,而不仅仅是正则表达式。

想到可以自动添加角色的唯一额外模式:

  1. 一个 + 在文字之后,例如上 A+ 添加一个 A
  2. 一般情况下最少发生,例如上 (?:foo){2,5} 加 foofoo 不要混淆 [fo]{2,5} 其中不能添加任何字符
  3. 在可变部分的最大长度之后的文字,例如,上 (?:foo){1,3}bar 加 bar 在文本之后 foofoofoo 在它不可能之前。
  4. 添加余数,例如 foo|bar 加 ar 什么时候 b 是键入和 oo 什么时候 f 是键入的(也可能在3中显示的模式中)但这不适用 ^[a-z]+?(?:foo|bar)$ 因为我们不知道用户何时计划结束文本并且它可能变得非常复杂(foo|flo|flu|food|fish 只要 sh 之后可以添加 fi)。

如在3.和4中所见,只要存在可变长度的部分,那些可以添加字符的附加情况的使用非常有限。您必须解析正则表达式,将其拆分为文字和正则表达式部分。然后你必须解析/分析正则表达式部分,以包含上面提到的可以添加字符的其他情况。如果你问我,真的不值得麻烦。 (您的电话模式中不能添加单个字符。)


1
2018-06-13 22:54