I am stuck with a NAME field, which typically is in the format:
FirstName LastName
然而,我也有偶尔出现的名称符合以下任意一种格式(包括前缀或后缀):
Mr. First Last
First Last Jr.
大家认为在PHP中将这些内容安全地拆分为名/姓变量的方法是什么?我无法想出一个能够始终正常工作的方法...
I am stuck with a NAME field, which typically is in the format:
FirstName LastName
然而,我也有偶尔出现的名称符合以下任意一种格式(包括前缀或后缀):
Mr. First Last
First Last Jr.
大家认为在PHP中将这些内容安全地拆分为名/姓变量的方法是什么?我无法想出一个能够始终正常工作的方法...
正则表达式是处理这种情况的最佳方法。 尝试使用以下代码段 - 它会提取前缀、名字、姓氏和后缀:
$array = array(
'FirstName LastName',
'Mr. First Last',
'First Last Jr.',
'Shaqueal O’neal',
'D’angelo Hall',
);
foreach ($array as $name)
{
$results = array();
echo $name;
preg_match('#^(\w+\.)?\s*([\'\’\w]+)\s+([\'\’\w]+)\s*(\w+\.?)?$#', $name, $results);
print_r($results);
}
结果如下:
FirstName LastName
Array
(
[0] => FirstName LastName
[1] =>
[2] => FirstName
[3] => LastName
)
Mr. First Last
Array
(
[0] => Mr. First Last
[1] => Mr.
[2] => First
[3] => Last
)
First Last Jr.
Array
(
[0] => First Last Jr.
[1] =>
[2] => First
[3] => Last
[4] => Jr.
)
shaqueal o’neal
Array
(
[0] => shaqueal o’neal
[1] =>
[2] => shaqueal
[3] => o’neal
)
d’angelo hall
Array
(
[0] => d’angelo hall
[1] =>
[2] => d’angelo
[3] => hall
)
在这个数组中,$array[0]
包含整个字符串。$array[2]
总是名字的第一部分,而 $array[3]
总是名字的最后一部分。
$array[1]
是前缀,$array[4]
(不总是设置)是后缀。
我还添加了代码来处理像 Shaqueal O’neal 和 D’angelo Hall 这样的名字,包括 ' 和 ’ 符号。
已接受的答案对于除英语以外的语言或像 "Oscar de la Hoya" 这样的名称无效。
这是我做的一些事情,我认为它是 utf-8 安全的,并适用于所有这些情况,建立在已接受的答案的假设上,即前缀和后缀将有一个句点:
/**
* splits single name string into salutation, first, last, suffix
*
* @param string $name
* @return array
*/
public static function doSplitName($name)
{
$results = array();
$r = explode(' ', $name);
$size = count($r);
//check first for period, assume salutation if so
if (mb_strpos($r[0], '.') === false)
{
$results['salutation'] = '';
$results['first'] = $r[0];
}
else
{
$results['salutation'] = $r[0];
$results['first'] = $r[1];
}
//check last for period, assume suffix if so
if (mb_strpos($r[$size - 1], '.') === false)
{
$results['suffix'] = '';
}
else
{
$results['suffix'] = $r[$size - 1];
}
//combine remains into last
$start = ($results['salutation']) ? 2 : 1;
$end = ($results['suffix']) ? $size - 2 : $size - 1;
$last = '';
for ($i = $start; $i <= $end; $i++)
{
$last .= ' '.$r[$i];
}
$results['last'] = trim($last);
return $results;
}
这是 PHP 单元测试:
public function testDoSplitName()
{
$array = array(
'FirstName LastName',
'Mr. First Last',
'First Last Jr.',
'Shaqueal O\'neal',
'D’angelo Hall',
'Václav Havel',
'Oscar De La Hoya',
'АБВГҐД ЂЃЕЀЁЄЖЗ', //cyrillic
'דִּיש מַחֲזֹור', //yiddish
);
$assertions = array(
array(
'salutation' => '',
'first' => 'FirstName',
'last' => 'LastName',
'suffix' => ''
),
array(
'salutation' => 'Mr.',
'first' => 'First',
'last' => 'Last',
'suffix' => ''
),
array(
'salutation' => '',
'first' => 'First',
'last' => 'Last',
'suffix' => 'Jr.'
),
array(
'salutation' => '',
'first' => 'Shaqueal',
'last' => 'O\'neal',
'suffix' => ''
),
array(
'salutation' => '',
'first' => 'D’angelo',
'last' => 'Hall',
'suffix' => ''
),
array(
'salutation' => '',
'first' => 'Václav',
'last' => 'Havel',
'suffix' => ''
),
array(
'salutation' => '',
'first' => 'Oscar',
'last' => 'De La Hoya',
'suffix' => ''
),
array(
'salutation' => '',
'first' => 'АБВГҐД',
'last' => 'ЂЃЕЀЁЄЖЗ',
'suffix' => ''
),
array(
'salutation' => '',
'first' => 'דִּיש',
'last' => 'מַחֲזֹור',
'suffix' => ''
),
);
foreach ($array as $key => $name)
{
$result = Customer::doSplitName($name);
$this->assertEquals($assertions[$key], $result);
}
}
如果你想简单地按以下方式分割名称:
你可以使用以下代码:
$firstName = substr($string, 0, strpos($string, ' '));
$lastName = substr($string, strlen($firstName));
这可能不是最复杂或文化敏感的方法,但只需两行代码,通常可以在不需要高度精确名称拆分的项目上完成工作。
这里有一个非常棒的库,迄今为止完美地解析了名字: https://github.com/joshfraser/PHP-Name-Parser
这不是一个简单的问题,而且在很大程度上,您能否得到可行的解决方案取决于文化“规范”。
First hive off any "honorifics" - using preg_replace
eg.
$normalized_name = preg_replace('/^(Mr\.*\sJustice|Mr\.*\s+|Mrs\.*\s+|Ms\.\s+|Dr\.*\s+|Justice|etc.)*(.*)$/is', '$2', trim($input_name));
Next hive off any trailing suffixes
$normalized_name = preg_replace('/^(.*)(Jr\.*|III|Phd\.*|Md\.)$/is', '$1', $normalized_name);
Finally split at the first blank to get a first name and last name.
显然,仅在英语中就有许多可能的敬语,我想不出太多的后缀,但可能比我列出的更多。
// First, just for safety make replacement '.' for '. '
$both = str_replace('.', '. ', $both);
// Now delete titles
$both = preg_replace('/[^ ]+\./', '', $both);
// Delete redundant spaces
$both = trim(str_replace(' ', ' ', $both));
// Explode
$split = explode(" ", $both, 2);
if( count($split) > 1 ) {
list($name, $surname) = $split;
} else {
$name = $split[0];
$surname = '';
}
首先你要分离FIRST/LAST,然后连接前缀。
以上是一个例子:
Vicent van Gogh
firstname 是数组的第一个索引。 在 firstname 之后的是 lastname,所以你只需要获取数组剩余的索引。
之后,你就可以连接前缀/后缀了。
Mr. Vicent van Gogh
Vicent van Gogh jr.
我总是建议尽可能从用户那里获取尽可能多的独立数据,同时只需要必要的数据以使函数正常工作。使用这种方法可以允许多种格式和名称构造方案。
在最终用户级别上独立捕获以下字段,很可能会消除解析的需要,或者至少清除特殊字符或拆分名称的解析问题,例如...“St. John”,“de la Hoya”和“Jr. III”。
一旦捕获了这些名称,程序员或最终用户(由程序员提供选项)可以根据需要动态重新排列、构造或格式化。