RegEx不适用于某些条件

时间:2017-09-15 14:56:44

标签: javascript regex

我必须验证项目中的名称字段,并且具有不同的验证条件。

起始名称:

  1. 最小。长度为2个字符。
  2. 可以是字母字符,空格和连字符。
  3. 第一个字母必须是字母。
  4. 空白&连字符不得相邻
  5. 我的正则表达式: -

    function fname(value){
    var fn = new RegExp("([a-zA-Z]{1}[a-zA-Z]*[ -]{0,1}[a-zA-Z])+([ -]{0,1}[a-zA-Z]+)*");
    if(fn.test(value)){
              return true;  
             }
             else{          
                return false;
             }
    }
    

    姓氏:

    1. 可以是字母字符,空格,连字符和撇号。
    2. 第一个字母必须是字母。
    3. 空白,连字符和撇号不得相邻。
    4. 只有当char为O
    5. 时才接受1个字符

      My Regex:

      function fname(value){
          var ln = new RegExp("([a-zA-Z]+([a-zA-Z]|([ '][a-zA-Z])|([-][a-zA-Z])){1,}|[O]{1})");
          if(ln.test(value)){
                    return true;  
                   }
                   else{          
                      return false;
                   }
          }
      

      这两个正则表达式都失败了,因为他们接受了:

      1. 字母数字字符变得可以接受,不应该是。
      2. 空格,连字符(在起始名称的情况下)和空格,连字符和撇号(在姓氏的情况下)在字符串中的任何位置。

3 个答案:

答案 0 :(得分:1)

虽然可以使用单个正则表达式完成,但最简单的解决方案是将测试分开:

function is_valid_first_name(str) {
    return (
        str.length >= 2 &&
        /^[a-zA-Z \-]*$/.test(str) &&
        /^[a-zA-Z]/.test(str) &&
        !/[ \-]{2}/.test(str)
    );
}

function is_valid_last_name(str) {
    return (
        /^[a-zA-Z \-']*$/.test(str) &&
        /^[a-zA-Z]/.test(str) &&
        !/[ \-']{2}/.test(str) &&
        (str.length > 1 || str === 'O')
    );
}

答案 1 :(得分:0)

首先,两个函数具有相同的名称。也许这只是一个错字。

无论如何,我认为这就是你想要的第一个名字。它不允许尾随空格或连字符,但似乎暗示了这一点。

const re_fname = /^[a-zA-Z](?:[- ]?|(?:[a-zA-Z][- ]?)+)$/;

function fname(value){
  const res = re_fname.test(value);
  console.log("%s: %s", res ? "PASS" : "FAIL", value);
  return res;
}

fname("foo-bar");
fname("foobar");
fname("f-");
fname("f--");
fname("foo-bar-");
fname("foo-bar--");
fname("-foo-bar");
fname("foo--bar");
fname("foo bar");
fname("foo  bar");
fname("foo- bar");

和姓氏几乎完全相同,只是将撇号添加到集合中,并允许单个O匹配。

const re_lname = /^(?:O|(?:[' -]?|[a-zA-Z](?:[' -]?[a-zA-Z])+)[' -]?)$/;
  
function lname(value){
  const res = re_lname.test(value);
  console.log("%s: %s", res ? "PASS" : "FAIL", value);
  return res;
}

lname("O");
lname("X");
lname("foobar");
lname("foo-bar");
lname("foo-bar-");
lname("foo-bar-'");
lname("foo-bar'");
lname("-foo-bar");
lname("foo--bar");
lname("foo bar");
lname("foo  bar");
lname("foo- bar");
lname("foo'bar");
lname("foo' bar");
lname("foo'- bar");
lname("foo-'bar");

答案 2 :(得分:0)

乍一看,我发现你没有在你的regexp中指定字符串边界的起点和终点,所以任何字符串 conatining 匹配的子字符串都会验证:

> "Hello".match(/[a-z]+/)
[ 'ello', index: 1, input: 'Hello' ]
> "Hello".match(/^[a-z]+$/)
null

我看到的另一个丑陋的东西是字符类([ -])中未转义的连字符。 即使在这种情况下也是有效的(它会像你期望的那样工作)但是很难看,因为它在角色类中具有特殊意义(取决于上下文),所以最小的和明显无害的变化可能会破坏已经在工作的东西:

> "-".match(/[abc-]/);
[ '-', index: 0, input: '-' ]
> "-".match(/[abc-j]/);
null

回答你的问题:忽略第4条规则很容易:

> "hello-world as foo".match(/^[a-zA-Z][a-zA-Z\s\-]+$/)
[ 'hello-world as foo', index: 0, input: 'hello-world as foo' ]
  • 第一个字符类([a-zA-Z])确保第二个规则并与规则n兼容。 1和3也是。

  • 第二个字符类([a-zA-Z\s\-])根据规则n匹配任何有效字符。 2。

  • 以下量词(+)确保一次或多次出现,加上初始字符类匹配的初始字符总和2个或更多字符(因此符合规则n.1)。

    < / LI>
  • 最后,开始和结束^$边界确保匹配从字符串的真正开始开始并在结束时结束,因此,正如我之前解释的那样,匹配子字符串不是& #39;足以验证是否存在无效字符。

第四条规则有点棘手。我认为它可以通过 lookbehind lookahead 表达式来处理,但它们并非在所有正则表达式引擎上都可用(即使在javascript中我认为它们至少在一些古老的版本)。

......而且,即使可用,它们也总是次优的(从正则表达式引擎实现的角度来看)。

另一方面,你可以依靠分组而不是将带有空格的组和带有连字符的组组合在一起的字符类,但这会使你的最终表达变暗,使其更难以构建,理解测试。因此,在我看来,它也不是一个好的解决方案。

但是如果您不被迫使用单个正则表达式,则可以通过临时表达式轻松区分。

function fname(value){
    return !!( // <- (optional) Boolean cast for more consistent return type.
        value.match(/^[a-zA-Z][a-zA-Z\s\-]+$/)
        && ! value.match(/\s-|-\s/)
    );
}

console.log (fname("hello-world as foo")); // true
console.log (fname("hello- world as foo")); // false
console.log (fname("hello -world as foo")); // false
console.log (fname("-hello-world as foo")); // false (null without "!!" cast).
console.log (fname(" hello-world as foo")); // false (null without "!!" cast).

...作为最后一点,我使用了&#34; \s&#34;字符类而不是&#34; &#34;对于空间。这也匹配其他间距字符(如标签,在某些情况下,换行符等等)如果您不想接受这些字符,请替换所有&#34; { {1}}&#34;通过简单的空间发生。

我更喜欢使用&#34; \s&#34;为了便于阅读(因为在大多数情况下,如果其他间距可以接受,我更喜欢它,但我认为在这种情况下它不是)。

  

姓氏规则几乎相同,因此根据相同的推理,所需的更改是微不足道的。