【问题标题】:Regular expression for getting first and last name ignoring middle names用于获取名字和姓氏忽略中间名的正则表达式
【发布时间】:2015-05-09 13:41:17
【问题描述】:

我正在搜索一个正则表达式,它可以在一个完整名称的字符串中为我提供名字和姓氏。

我进行了搜索,但没有找到适合我需要的。例如:

  • Abc Def Ghi Jkl ---> Abc Jkl
  • Aéc Def Gài Mkl ---> Aéc Mkl
  • Aéc-Def Gài Mkl ---> Aéc-Def Mkl
  • Aéc Def Gài-Mkl ---> Aéc Gài-Mkl
  • Afd ---> Afd

当字符串是左侧的内容时,如何构建正则表达式以返回右侧的内容?

【问题讨论】:

  • 既然可以拆分字符串并获取第一个和最后一个索引,为什么还要使用正则表达式。
  • @jeff 我可以这样做,但我想更好地了解正则表达式的工作原理,并通过一些实际示例更容易;)
  • "更容易" - 不,不是。
  • 这可能是对 split 的更好使用,但我看到 split 被滥用得更多,因为人们将其用作避免正则表达式的拐杖。

标签: javascript regex


【解决方案1】:

对于您有不同字符的特定情况,您必须稍微更改正则表达式以满足您的需要,这里有一个可以满足您的需要:

^([\w-éà]+)[^\w-éà].*?[^\w-éà]([\w-éà]+)$|^([\w-éà]+)$

在 regex101.com 上测试:

解释:

我们必须将正则表达式分成两部分以便于理解:

^([\w-éà]+)[^\w-éà].*?[^\w-éà]([\w-éà]+)$

这是您至少有两个名字的一般情况。

块 [\w-éà] 代表你的字符集。

然后您使用起始锚 (^) 告诉引擎您正在寻找行首的匹配项,然后您会得到一个包含您的字符集的组,直到您找到不在您的字符中的内容设置([^\w-éà])。然后你使用惰性量词。*?匹配下一个模式的第一次出现,即匹配一个单词到结束锚($)。

第二部分只是一个单词大小写(^([\w-éà]+)$)

在这个例子中,当至少有两个名字时,第 1 组将有名字

当至少有两个名字时,第 2 组将有姓氏

当只有一个名字时,第 3 组将有名字

【讨论】:

    【解决方案2】:

    虽然我不建议为此使用正则表达式,但以下使用 String.prototype.split()Array.prototype.shift()Array.prototype.forEach() 似乎更容易:

    function firstAndLast(el) {
      // getting the text of the element:
      var haystack = el.textContent,
        // splitting that text on white-space sequences,
        // forming an array:
        names = haystack.split(/\s+/),
        // getting the first element of that array:
        first = names.shift(),
        // initialising the 'last' variable to an empty string:
        last = '';
      // if the names array has a length greater than 1
      // (there is more than one name):
      if (names.length > 1) {
        // last is assigned the last element of the array of names:
        last = names.pop();
      }
    
      // return an array containing the first and last names:
      return [first, last];
    }
    
    // getting all the <li> elements in the document:
    var listItems = document.querySelectorAll('li'),
      // creating an empty <span> element:
      span = document.createElement('span'),
      // an unitialised variable for use within the loop:
      clone;
    
    // iterating over each of the <li> elements, using
    // Array.prototype.forEach(), and Function.prototype.call():
    Array.prototype.forEach.call(listItems, function(li) {
      // cloning the created <span>:
      clone = span.cloneNode();
      // setting the clone's text to the joined-together
      // strings from the Array returned by the function:
      clone.textContent = firstAndLast(li).join(' ');
      // appending that cloned created-<span> to the
      // current <li> element over which we're iterating:
      li.appendChild(clone);
    });
    

    function firstAndLast(el) {
      var haystack = el.textContent,
        names = haystack.split(/\s+/),
        first = names.shift(),
        last = '';
      if (names.length > 1) {
        last = names.pop();
      }
    
      return [first, last];
    }
    
    var listItems = document.querySelectorAll('li'),
      span = document.createElement('span'),
      clone;
    
    Array.prototype.forEach.call(listItems, function(li) {
      clone = span.cloneNode();
      clone.textContent = firstAndLast(li).join(' ');
      li.appendChild(clone);
    });
    li span::before {
      content: ' found: ';
      color: #999;
    }
    li span {
      color: #f90;
      width: 5em;
    }
    <ol>
      <li>Abc Def Ghi Jkl</li>
      <li>Aéc Def Gài Mkl</li>
      <li>Aéc-Def Gài Mkl</li>
      <li>Aéc Def Gài-Mkl</li>
      <li>Afd</li>
    </ol>

    JS Fiddle demo.

    可以使用正则表达式,只是不必要地更复杂:

    function firstAndLast(el) {
      var haystack = el.textContent,
        // matching a case-insensitive sequence of characters at the
        // start of the string (^), that are in the range a-z,
        // unicode accented characters, an apostrophe or
        // a hyphen (escaped with a back-slash because the '-'
        // character has a special meaning within regular
        // expressions, indicating a range, as above) followed
        // by a word-boundary (\b):
        first = haystack.match(/^[a-z\u00C0-\u017F'\-]+\b/i),
    
        // as above but the word-boundary precedes the string of
        // of characters, and it matches a sequence at the end
        // of the string ($):
        last = haystack.match(/\b[a-z\u00C0-\u017F'\-]+$/i);
    
      // if first exists (no matching regular expression would
      // would return null) and it has a length:
      if (first && first.length) {
        // we assign the first element of the array returned by
        // String.prototype.match() to the 'first' variable:
        first = first[0];
      }
      if (last && last.length) {
        // as above:
        last = last[0];
      }
    
      // if the first and last variables are exactly equal,
      // we return only the first; otherwise we return both
      // first and last, in both cases within an array:
      return first === last ? [first] : [first, last];
    }
    

    function firstAndLast(el) {
      var haystack = el.textContent,
        first = haystack.match(/^[a-z\u00C0-\u017F'\-]+\b/i),
        last = haystack.match(/\b[a-z\u00C0-\u017F'\-]+$/i);
      if (first && first.length) {
        first = first[0];
      }
      if (last && last.length) {
        last = last[0];
      }
      return first === last ? [first] : [first, last];
    }
    
    var listItems = document.querySelectorAll('li'),
      span = document.createElement('span'),
      clone;
    
    Array.prototype.forEach.call(listItems, function(li) {
      clone = span.cloneNode();
      clone.textContent = firstAndLast(li).join(' ');
      li.appendChild(clone);
    });
    li span::before {
      content: ' found: ';
      color: #999;
    }
    li span {
      color: #f90;
      width: 5em;
    }
    <ol>
      <li>Abc Def Ghi Jkl</li>
      <li>Aéc Def Gài Mkl</li>
      <li>Aéc-Def Gài Mkl</li>
      <li>Aéc Def Gài-Mkl</li>
      <li>Afd</li>
    </ol>

    JS Fiddle demo.

    参考资料:

    【讨论】:

      【解决方案3】:

      我会使用 ^ 来匹配输入的开头,然后使用括号 () 、特殊的 \w 字符和 + 字符来捕获名字。然后是可选的空格/字符,后跟更多的括号来捕获输入结束之前的姓氏,它与特殊的$ 字符匹配。这是一个例子:

      var huge = 'Abc Def Ghi Jkl';
      var small = 'Afd';
      
      var regex = /^(\w+).*?(\w*)$/;
      var results = regex.exec(huge);
      
      console.log(results[1]); // 'Abc'
      console.log(results[2]); // 'Jkl'
      
      var results = regex.exec(small);
      
      console.log(results[1]); // 'Afd'
      

      有很多方法可以做你想做的事,所以我推荐阅读this page

      【讨论】:

        【解决方案4】:

        如果您只为正则表达式传递一个全名,请使用该全名来获取名字和姓氏 /^[^ \n]+|[^ \n]+$/g ,如果您要传递由每个全名之间的行分隔的所有全名列表,请使用此 /^[^ \n]+|[^ \n]+$/gm 只需在正则表达式末尾添加 m 使用此链接进行测试 regex to get first and last name from a full name

        【讨论】:

          【解决方案5】:

          请记住,结构良好的 Regex 不仅应涵盖当前现有示例,还应涵盖尽可能多的例外情况——此外,它的设计方式还应便于将来扩展!在 JS 中你可以试试下面的正则表达式:

          var re = /^(\w+(-\w+)? ?)((.* )(?!$))?(\w+(-\w+)?)$/;
          var strLong = "Abc_Def-John with a Really really_LongName";
          var newstrLong = strLong.replace(re, "$1$5");
          console.log(newstrLong);
          
          var strShort = "simplyJohn";
          var newstrShort = strShort.replace(re, "$1$5");
          console.log(newstrShort);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-14
            相关资源
            最近更新 更多