如何将全名拆分为单名、中名和姓氏?
显然,不可能涵盖所有可能性。我只想要一个规则:如果单词后面有3个字母或更少的单词,它必须与下一个单词连接。
另外,我假设全名有 3 个或更多单词。
我真的不知道如何开始。
例如:
约翰马丁杰克逊:
- 姓名1:约翰
- 姓名2:马丁
- 姓名3:杰克逊
史蒂文庞塞德莱昂普雷斯利
- 姓名1:史蒂文
- 名称2:庞塞德莱昂
- 名称3:普雷斯利
迈克尔·德拉罗莎·马丁·杰克逊:
- 姓名 1:迈克尔·德拉·罗莎
- 姓名2:马丁
- 姓名3:杰克逊
:S
如何将全名拆分为单名、中名和姓氏?
显然,不可能涵盖所有可能性。我只想要一个规则:如果单词后面有3个字母或更少的单词,它必须与下一个单词连接。
另外,我假设全名有 3 个或更多单词。
我真的不知道如何开始。
例如:
约翰马丁杰克逊:
史蒂文庞塞德莱昂普雷斯利
迈克尔·德拉罗莎·马丁·杰克逊:
: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+)*)$/
要使其匹配没有中间名的人,请将其设为可选:
/^(\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
这样的事情怎么样?
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 个以上的名称。您将不得不考虑如何处理。
这是另一个工作功能http://jsfiddle.net/xPzEs/7/
编辑:坏链接