1

如何将全名拆分为单名、中名和姓氏?

显然,不可能涵盖所有可能性。我只想要一个规则:如果单词后面有3个字母或更少的单词,它必须与下一个单词连接。

另外,我假设全名有 3 个或更多单词。

我真的不知道如何开始。

例如:

约翰马丁杰克逊:

  • 姓名1:约翰
  • 姓名2:马丁
  • 姓名3:杰克逊

史蒂文庞塞德莱昂普雷斯利

  • 姓名1:史蒂文
  • 名称2:庞塞德莱昂
  • 名称3:普雷斯利

迈克尔·德拉罗莎·马丁·杰克逊:

  • 姓名 1:迈克尔·德拉·罗莎
  • 姓名2:马丁
  • 姓名3:杰克逊

:S

4

3 回答 3

3

一个非常漂亮的正则表达式可以做到这一点。要匹配一个名称,请使用

/\S+((\s+\S{1,3})+\s+\S+)*/

然后,将其中三个与不匹配的组组合在一起,但每个组都包含在一个中,并由空格连接:

/^(\S+(?:(?:\s+\S{1,3})+\s+\S+)*)\s+(\S+(?:(?:\s+\S{1,3})+\s+\S+)*)\s+(\S+(?:(?:\s+\S{1,3})+\s+\S+)*)$/

要使其匹配没有中间名的人,请将其设为可选:

/^(\S+(?:(?:\s+\S{1,3})+\s+\S+)*)(?:\s+(\S+(?:(?:\s+\S{1,3})+\s+\S+)*))?\s+(\S+(?:(?:\s+\S{1,3})+\s+\S+)*)$/

更新:不要尝试在一个正则表达式中匹配全名。只需使用带有全局标志的第一个(简单)正则表达式:

> "Steven Ponce de Leon Presley".match(/\S+((\s+\S{1,3})+\s+\S+)*/g)
["Steven", "Ponce de Leon", "Presley"]

解释:

/
 \S+      match a word
 (         followed by any number of
  (         at least one
   \s+       whitespace-separated
   \S{1,3}   up-to-three-letters word
  )+
  \s+       and a whitespace-separated
  \S+       word
 )*
/g

但是,我认为具有一些字符串和数组函数的算法会使发生的事情更清楚,并允许更多地自定义匹配过程:

var names = input.split(/s+/);
if (names.length < 2)
    return; // special case handling for only one word
var short = 0;
for (var i=names.length-2; i>=0; i--) {
    // starting at the second-to-last, I expect names not to end with a short one
    if (names[i].length < 4) {
        short++;
    } else if (short) {
        names[i] += " "+names.splice(i+1, short+1).join(" ");
        short = 0;
    }
}
return names; // an Array with at least one name
于 2012-08-02T23:05:13.750 回答
1

这样的事情怎么样?

function split_name(name) {
    var parts = name.split(" ");
    var num_parts = parts.length;
    var i = 0;
    var names = [];

    function in_bounds() {
        return i < num_parts;
    }
    function next_part() {
        i += 1;
        return parts[i - 1];
    }
    function part_is_short() {
        return parts[i].length < 4;
    }
    function last_part_was_short() {
        return parts[i-1].length < 4;
    }
    function next_name() {
        var name = next_part();
        if (in_bounds() && part_is_short()) {
            name += " " + next_part();
            while(in_bounds() && last_part_was_short()) {
                name += " " + next_part();
            }
        }
        return name;
    }

    while (in_bounds()) {
        names.push(next_name());
    }

    return names;
}

JSFiddle:http: //jsfiddle.net/nLe7S/2/

它不是有史以来性能最高的算法。正则表达式大师可能会在一行中做同样的事情,但至少这种方式对我们凡人来说是可读的。更新:我看到 Bergi刚刚证明自己是一位正则表达式大师。:)

它大致完成了您所描述的工作,但您必须根据您的需要对其进行调整。例如,它返回一个包含与它找到的一样多的“子名称”的数组。因此,如果找不到中间名,它将返回一个长度为 2 的数组。另一方面,它可能会找到 3 个以上的名称。您将不得不考虑如何处理。

于 2012-08-02T23:08:18.563 回答
1

这是另一个工作功能http://jsfiddle.net/xPzEs/7/

编辑:坏链接

于 2012-08-02T23:53:10.590 回答