我正在进行网站迁移,涉及从fullname中提取firstname和lastname。鉴于这些是由最终用户创建的,存在各种排列(尽管英语并且通常不太奇怪)。大多数情况下,我可以将第一个单词作为名字,将最后一个单词作为姓氏,但偶尔使用前缀和后缀。在浏览数据并试图了解所有可能的异常时,我意识到这是一个至少部分解决过很多次的常见问题。
在重新发明轮子之前,是否有人有任何适合他们的正则表达式或有用的代码?性能不是考虑因素,因为这是一次性的实用程序。
要处理的典型值:
杰森布里格斯, J.D.史密斯, John Y Citizen, J Scott Myers, 比尔杰克逊三世, 约翰米尔斯先生
更新:虽然是一个常见问题,但典型的解决方案似乎涉及处理大多数情况并手动清理其余情况。
(考虑到必须经历这个问题的频率,我原本希望在那里找到一个实用程序库但是我自己找不到谷歌了)
答案 0 :(得分:11)
我的建议如下:
拆分空格上的名称。
检查返回数组的长度。如果2,容易拆分。如果更多,接下来。
比较前缀的第一个值(即Mr. Mrs. Dr. Dr。)......如果是,请将其删除,否则转到下一个。
比较第一个长度值。如果它只是1个字符,则组合数组中的前2个项目。
它仍然不是万无一失的;但是,它应该解决至少80%的案件。
希望这有帮助。
答案 1 :(得分:6)
可能无法做到(可靠)。
即使你能为某些名字做到这一点,你也会在某个时候找到一个西班牙人,他们会记下这两个姓氏。或者某些人(忘了它的国籍)将放入“姓氏名字”。或许多其他情况之一...
你可以做的最好的事情就是将2个单词作为名字和姓氏分开,然后手动完成其余部分(自己,或聘请一些专业人士)......
答案 2 :(得分:6)
最快的事情是混合算法 - 人类方法。你不想花时间整理一个99.99%的时间工作的系统,因为最后5-10%的优化会杀了你。此外,你不想只是将所有工作都转储给一个人,因为大多数情况(我猜)都相当简单。
因此,快速构建类似于JamesEggers建议的内容,但要抓住所有看似不寻常或不符合预定义转换的情况。然后,只需手动完成这些案例(不应该太多)。
您可以通过在Mechanical Turk中设置HIT来自行审核这些案例或将其外包给其他用户:
(假设500个案件的价格为0.05美元(高额奖励),您的总费用最多为25美元)
答案 3 :(得分:2)
答案 4 :(得分:2)
这是一个不确定的问题(或者我喜欢称之为Oracle问题)并且以可靠的方式无法解决。这是因为存在名字的名字,如名字和姓氏,例如,斯坦利,杰克逊等。但是可以尝试一下。您需要编写一个学习程序,该程序将被赋予一组名字和姓氏,并且它将维护这些名称的字典,并根据它作为名字的概率进行映射。
现在,传递您要迁移的所有值,并使用这些概率,您可以在名字和名字之间得到合理的分割。此外,如果一个特定的名称变得模棱两可(完全取决于你定义模糊,但我会将其定义为我获得的所有概率值的底部30%),那么你可以标记它以供日后查看。
希望这有帮助。
干杯!
答案 5 :(得分:1)
如果您只有少数用户(<100k),那么看看您是否可以让某人手动完成,并将时间花在有价值的事情上。由于这是一次性工作,投资回报很糟糕: - )
答案 6 :(得分:1)
我挖出了一个非常简单的(80%可能)我在perl中使用的正则表达式,并添加了一些快乐的C#组名称:
(?<title>(mr|ms|mrs|miss|dr|hon)\.?\s+)?(?<firstandmiddle>.+)\s+(?<last>((van|de|von)\s+)?\S+)(?<junior>\s+(jr|sr|ii|iii|iv)\.?)
我发布的是wiki,所以任何人都可以随意添加他们认为有用的内容!
答案 7 :(得分:1)
正如其他人指出的那样,没有适用于所有情况的解决方案。 其中一个原因是有名称可以作为名字和姓氏使用。
您可以使用名字数据库,并找出名称的哪个部分可能是名字。如果您也知道具有特定姓名的人的国家/地区,则可以提高准确性。
有关名字的免费数据库,请参阅this answer。
答案 8 :(得分:1)
如果您的数据世界是&lt; 10k名称并且它的一次性交易将其他海报描述的分割场景之一实现为中间文件,那么请手动查看并在必要时进行更新(您会感到惊讶的审核10k名称需要很少的时间)。与尝试查找和构建完美实现的算法相比,您将花费更少的时间。一旦您的名称范围> 100k,那么它值得尝试编写您的方法并将文件分离出来进行人工审核并修改所有不能给您完美名字的名称,姓氏分开。
答案 9 :(得分:1)
static void CheckSuffix(ref string[] sArrName)
{
// Initialize suffixes
List<string> Suffixes = new List<string>();
Suffixes.Add("jr");
Suffixes.Add("sr");
Suffixes.Add("esq");
Suffixes.Add("ii");
Suffixes.Add("iii");
Suffixes.Add("iv");
Suffixes.Add("v");
Suffixes.Add("2nd");
Suffixes.Add("3rd");
Suffixes.Add("4th");
Suffixes.Add("5th");
int i = 0; string suffix = string.Empty; foreach (string s in sArrName) { string[] schk = s.ToLower().Split(new char[] { ' ' }); foreach (string sverifiy in schk) { if (Suffixes.Contains(sverifiy)) { suffix = sverifiy; sArrName[i] = sArrName[i].Replace(sverifiy.ToUpper(), string.Empty).Trim(); }; } i += 1; } sArrName[2] = string.Format("{0}{1}", sArrName[2], (!string.IsNullOrEmpty(suffix) ? " " + suffix.ToUpper() + "." : string.Empty)); } public static string[] ExtractFullname(string name) { string[] sArr = { "", "", ""}; string[] sName = name.Split(new char[] { ' ', ',', '.' }, StringSplitOptions.RemoveEmptyEntries); int chkinitial = -1; for (int i = 0; i < sName.Length; i++) { if (sName[i].Length == 1) chkinitial = i; } switch (sName.Length) { case 1: sArr[0] = name; break; case 2: { int idx = name.IndexOf(','); if (idx != -1 && idx < name.Length) { sArr[0] = sName[1]; sArr[2] = sName[0]; } /* last, first */ else { idx = name.IndexOf(' '); if (idx != -1 && idx < name.Length) { sArr[0] = sName[0]; sArr[2] = sName[1]; } /* first last */ } } break; case 3: if (chkinitial == 1) { sArr[0] = sName[0]; sArr[1] = sName[1]; sArr[2] = sName[2]; } /* first middle last */ else if (chkinitial == 2) { sArr[0] = sName[1]; sArr[1] = sName[2]; sArr[2] = sName[0]; } /* last first middle */ else if (chkinitial == -1) { int idx = name.IndexOf(','); if (idx != -1) { if (idx == (sName[0].Length + sName[1].Length + 1)) { sArr[0] = sName[2]; sArr[2] = string.Format("{0} {1}", sName); } else { sArr[0] = string.Format("{1} {2}", sName); sArr[2] = sName[0]; } } else { sArr[0] = name; } } break; case 4: if (chkinitial == 1) { sArr[0] = sName[0]; sArr[1] = sName[1]; sArr[2] = string.Format("{2} {3}", sName); } /* first middle last */ else if (chkinitial == 2) { sArr[0] = string.Format("{0} {1}", sName); sArr[1] = sName[2]; sArr[2] = sName[3]; } /* last first middle */ else if (chkinitial == 3) { int idx = name.IndexOf(','); if (idx != -1) { if (idx == (sName[0].Length + sName[1].Length + 1)) { sArr[0] = sName[2]; sArr[1] = sName[3]; sArr[2] = string.Format("{0} {1}", sName); } else { sArr[0] = string.Format("{1} {2}", sName); sArr[1] = sName[3]; sArr[2] = sName[0]; } } else { sArr[0] = name; } } else if (chkinitial == -1) { int idx = name.IndexOf(','); if (idx != -1) { if (idx == (sName[0].Length)) { sArr[0] = string.Format("{1} {2} {3}", sName); sArr[2] = sName[0]; } else if (idx == (sName[0].Length + sName[1].Length + 1)) { sArr[0] = string.Format("{2} {3}", sName); sArr[2] = string.Format("{0} {1}", sName); } else if (idx == (sName[0].Length + sName[1].Length + sName[2].Length + 1)) { sArr[0] = sName[3]; sArr[2] = string.Format("{0} {1} {2}", sName); } else { sArr[0] = name; } } else { sArr[0] = name; } } break; default: /* more than 3 item in array */ sArr[0] = name; break; } CheckSuffix(ref sArr); return sArr; }