本当に凝った正規表現がそれを可能にします。1 つの名前に一致させるには、次を使用します。
/\S+((\s+\S{1,3})+\s+\S+)*/
次に、それらの 3 つを一致しないグループと結合しますが、それぞれが 1 つにまとめられ、空白で結合されます。
/^(\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+)*)$/
更新: 1 つの正規表現で名前全体を一致させようとしないでください。グローバル フラグを指定して最初の (単純な) 正規表現を使用するだけです。
> "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