search

Home  >  Q&A  >  body text

正则正向否定匹配怎么用?

比如匹配至少不能全是大写字母或者全是小写字母或者全是数字

(?!^[A-Z]+$|^[a-z]+$|^[0-9]+$)^\S+$

问什么不能使用呢


高洛峰高洛峰2942 days ago854

reply all(4)I'll reply

  • 欧阳克

    欧阳克2016-11-10 16:53:46

    UPDATE: 之前的补充可能不对。
    /(?!)/这类断言的不实际匹配字符,常常是组合式使用的。举例
    /(.*)(?!00$)/以00结尾的字符,貌似反义的(?!)不被支持。

    请忽略下面的补充吧,我也不删除了。说说题主的正则的可能的问题

    reg = /(?!^[A-Z]+$|^[a-z]+$|^[0-9]+$)/
    reg.test("11") //true
    
    //修改后
    reg = /^(?![A-Z]+$|[a-z]+$|[0-9]+)$/
    reg.test("11") //false
    reg.test("1a") //true

    回答题主的另外一个问题,
    请问一下,正想否定匹配不是不消耗字符吗,为什么这样可以呢
    我做了简单实验,首先

    var re1 = /(^\d$|^[a-z]$)/; //分支形式,匹配一个数字或者一个小写字母
    re1.test("1");
    re1.test("a");
    re1.test("1a"); // false
    //以上结果如我们所愿的

    然后是否定的分支

    var re2 = /(?!^\d$|^[a-z]$)/;
    re2.test("1"); //true
    re2.test("aaa"); //true
    re2.test("1111"); //true
    re2.test(" "); //true

    其实这是一个语法上的问题,上面的分支其实是由/(?!^\d$)/和/^[a-z]$/组成的。
    但我在这里强烈建议不要写出/(?!^\d$)/这样的正则出来
    因为它能匹配任意字符,任意长度的。
    因为它是断言不实际匹配字符,或者说匹配某个位置,要找出不是/^\d$/这样的位置出来太简单了。
    假设^.*$这样的字符串,只要在$的位置去match上面的/^\d$/当然是不会匹配的啦。

    那么正确的写法应该怎样的呢?

    var re3 = /(?!(^\d$|^[a-z]$))./;
    re3.test("1"); // false
    re3.test("a"); // false
    re3.test(" "); //true

    这样组合式的写法也有它的问题,整个正则限制了只能匹配一个字符,这个字符不是能是数字和小写字母。

    进一步看,明白了(?!)的语法,是可以对^和$做适当的提取的。


    reply
    0
  • 三叔

    三叔2016-11-10 16:52:24

    听起来像是用来检测密码复杂度的。python 字符串内置方法isupper islower isdigit

    reply
    0
  • 欧阳克

    欧阳克2016-11-10 16:52:15

    (?!1+$|2+$|3+$)^S+$

    A-Z ↩

    a-z ↩

    0-9 ↩


    reply
    0
  • 三叔

    三叔2016-11-10 16:51:26

    试试这个[a-zA-Z0-9]*呢

    reply
    0
  • Cancelreply