【问题标题】:Separate firstname and lastname from fullname string in C#在 C# 中将名字和姓氏与全名字符串分开
【发布时间】:2009-08-02 15:10:52
【问题描述】:

我正在进行网站迁移,其中涉及从全名中提取名字和姓氏。鉴于这些是由最终用户创建的,存在各种排列(尽管是英语并且通常不会太奇怪)。大多数情况下,我可以将第一个单词作为名字,将最后一个单词作为姓氏,但偶尔的前缀和后缀有一些例外。在浏览数据并试图了解所有可能的例外情况时,我意识到这是一个常见问题,之前至少已经部分解决了很多次。

在重新发明轮子之前,有没有人有任何对他们有用的正则表达式或有用的代码?性能不是考虑因素,因为这是一次性实用程序。

要处理的典型值:

杰森布里格斯, J.D.史密斯, 约翰·Y·公民, J斯科特迈尔斯, 比尔·杰克布森三世, 约翰·米尔斯先生


更新:虽然是一个常见问题,但典型的解决方案似乎涉及处理大多数情况并手动清理其余情况。

(考虑到这个问题必须经历的频率,我原本希望在那里找到一个实用程序库,但我自己无法通过 Google 找到一个)

【问题讨论】:

  • 数据库中有多少个名字?
  • 大约 10K,因此使用处理 95% 情况的解决方案进行手动检查仍然是可行的。使用第一个和最后一个词处理了大约 85% 的名称。

标签: c# regex string


【解决方案1】:

我的建议如下:

  1. 在空格上拆分名称。

  2. 检查返回数组的长度。如果2,容易分裂。如果更多,下一个。

  3. 比较前缀的第一个值(即 Mr. Mrs. Ms. Dr.)...如果是,则将其删除,否则移至下一个。

  4. 比较第一个值的长度。如果只有 1 个字符,则合并数组中的前 2 个项目。

这仍然不是万无一失的;但是,它应该至少能解决您 80% 的案件。

希望这会有所帮助。

【讨论】:

  • 我同意这一点,如果您可以将数据分解为各种可靠解析的数据集,您可能会发现剩余的“故障案例”小到可以人工处理。
  • James - 感谢您非常实用的想法。鉴于数据总体上相当不错,我认为这应该可以解决约 95% 的情况。
【解决方案2】:

这可能是不可能的(可靠的)。

即使您可以为某些名字这样做,您也会在某个时候得到一个西班牙人,他会写下两个姓氏。或者有些人(忘记了它是哪个国籍)会输入“姓氏名字”。或许多其他情况之一...

您可能会做的最好的事情是将 2 个单词分别作为名字和姓氏,然后手动检查其余部分(您自己,或聘请一些专业人员)...

【讨论】:

  • 我认为你是对的。正如 Apoorv 指出的那样,语言排列和非结构化的性质导致这是一个不确定的问题。
  • 别忘了 O'Neill、Van Der Spek、Van Eck、Hart-Mahon 和 de la Cruz 等姓氏......
【解决方案3】:

最快的方法是混合算法-人工方法。您不想花时间组装一个在 99.99% 的时间内都可以工作的系统,因为最后 5-10% 的优化会杀死您。此外,您不想将所有工作都转嫁给一个人,因为大多数情况(我猜)都相当简单。

因此,快速构建类似于 JamesEggers 建议的内容,但要捕获所有看起来不寻常或不符合您预定义转换的情况。然后,只需手动处理这些案例(不应该太多)。

您可以自己处理这些案例,也可以通过在 Mechanical Turk 中设置 HIT 将其外包给其他用户:

http://aws.amazon.com/mturk/

(假设 500 个案例,0.05 美元(高回报),您的总成本最多应为 25 美元)

【讨论】:

    【解决方案4】:

    如果这是一次性交易,那么我强烈考虑付钱给其他专家为您做这件事。

    他们将在处理结构不佳的数据集方面经验丰富。

    我与他们没有任何关系,但 Melissa Data 提供的服务似乎是为这类事情量身定制的。

    【讨论】:

      【解决方案5】:

      这是一个不确定的问题(或者我喜欢称之为 Oracle 问题)并且无法以可靠的方式解决。这是因为存在既是名字又是姓氏的名字,例如斯坦利、杰克逊等。但可以尝试一下。您需要编写一个学习程序,该程序将获得一组名字和姓氏,并且它将维护这些名字的字典,映射到它是名字的概率。

      现在,传递要迁移的所有值,并使用这些概率,您可以合理地划分名字和姓氏。此外,如果某个特定名称变得模棱两可(完全由您来定义模棱两可,但我会将其定义为我获得的所有概率值的底部 30 个百分位数),那么您可以标记它以供稍后查看。

      希望这会有所帮助。

      干杯!

      【讨论】:

      • 此外,对于 J.D. Smith 这样的案例,您可以主要将 J.D. 视为名字,将 Smith 视为姓氏。
      【解决方案6】:

      如果您只有几个用户(

      【讨论】:

      • 大约有 10K 用户,所以你可能是对的 - 这是不合理的程序员强迫花费 5 个小时试图解决一半的边缘案例,而实习生需要一个小时的“手动”清理.
      • 完全正确 ;-) 我只知道很清楚
      【解决方案7】:

      我在 perl 中找到了一个非常简单(可能是 80%)的正则表达式,并添加了一些快乐的 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 的形式发帖,所以任何人都可以随意添加他们认为有帮助的内容!

      【讨论】:

      • 谢谢 Mike,我会看看我的数据如何处理。
      【解决方案8】:

      正如其他人指出的那样,没有适用于所有情况的解决方案。 这样做的一个原因是,有些名字既可以用作名字,也可以用作姓氏。

      您可以使用名字数据库并找出名字的哪些部分可能是名字。如果您还知道具有特定姓名的人的国家/地区,则可以大大提高准确性。

      如需免费的名字数据库,请参阅this answer

      【讨论】:

        【解决方案9】:

        如果您的数据世界是 100k,那么就值得尝试通过编程来摆脱它并分离出一个文件,以便手动审查和修改所有不给您完美的名字,姓氏拆分的名字。

        【讨论】:

          【解决方案10】:

          static void CheckSuffix(ref string[] sArrName) { // Initialize suffixes List&lt;string&gt; Suffixes = new List&lt;string&gt;(); 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; }

          【讨论】:

            猜你喜欢
            • 2011-10-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-07
            • 2021-06-16
            • 1970-01-01
            相关资源
            最近更新 更多