Подтвердить что ты не робот

Простой способ проанализировать имя человека в его составных частях?

Многие программы управления контактами делают это - вы вводите имя (например, "John W. Smith" ), и оно автоматически разбивает его внутри:

Имя: Джон
Отчество: W.
Фамилия: Смит

Аналогично, он определяет такие вещи, как "Миссис Джейн У. Смит" и "Доктор Джон Доу-младший" (при условии, что вы допускаете такие поля, как "префикс" и "суффикс" в именах).

Я предполагаю, что это довольно распространенные вещи, которые люди хотели бы сделать... так что вопрос... как бы вы это сделали? Есть ли простой алгоритм для этого? Может быть, регулярное выражение?

Я после .NET-решения, но я не придирчив.

Обновление: Я ценю, что для этого нет простого решения, которое охватывает ВСЕ крайние случаи и культуры... но позвольте сказать, ради аргумента, что вам нужно имя в кусках (заполнение формы - как, например, в налоговых или других государственных формах - это один случай, когда вы обязаны вводить имя в фиксированные поля, нравится вам это или нет), но вы не обязательно хотите заставить пользователя вводить их имя в дискретные поля (меньше ввода = проще для начинающих пользователей).

Вы хотели бы, чтобы программа "угадывала" (насколько это возможно) на том, что первое, среднее, последнее и т.д. Если можно, посмотрите, как Microsoft Outlook делает это для контактов - он позволяет вам вводить имя, но если вам нужно уточнить, есть дополнительное маленькое окно, которое вы можете открыть. Я бы сделал то же самое - дайте пользователю окно, если они захотят ввести имя в отдельные части, - но разрешите вводить имя в одном поле и делать "лучшее предположение", которое охватывает наиболее распространенные имена.

4b9b3361

Ответ 1

Для этого нет простого решения. Создание имени варьируется от культуры к культуре, и даже в англоязычном мире существуют префиксы и суффиксы, которые не обязательно являются частью имени.

Основной подход заключается в поиске honififics в начале строки (например, "Hon. John Doe") и чисел или некоторых других строк в конце (например, "John Doe IV", "John Doe Jr."), но на самом деле все, что вы можете сделать, это применить набор эвристик и надеяться на лучшее.

Может быть полезно найти список необработанных имен и проверить ваш алгоритм на его соответствие. Я не знаю, что там что-то было заранее упаковано.

Ответ 2

Если вы должны сделать этот синтаксический анализ, я уверен, что здесь вы получите много хороших предложений.

Мое предложение - не выполнять этот синтаксический анализ.

Вместо этого создайте поля ввода, чтобы информация уже была отделена. Имеют отдельные поля для названия, имени, среднего начального, фамилии, суффикса и т.д.

Ответ 3

Я знаю, что это старое и может быть ответом где-то, чего я не мог найти, но так как я не мог найти ничего, что сработает для меня, это то, что я придумал, и я думаю, что это очень похоже на Google Contacts и Microsoft Outlook. Он отлично справляется с краевыми случаями, но для хорошего приложения типа CRM пользователя всегда можно попросить разрешить его (в моем приложении у меня есть отдельные поля все время, но мне нужно это для импорта данных из другого приложения, которое имеет только одно поле):

    public static void ParseName(this string s, out string prefix, out string first, out string middle, out string last, out string suffix)
    {
        prefix = "";
        first = "";
        middle = "";
        last = "";
        suffix = "";

        // Split on period, commas or spaces, but don't remove from results.
        List<string> parts = Regex.Split(s, @"(?<=[., ])").ToList();

        // Remove any empty parts
        for (int x = parts.Count - 1; x >= 0; x--)
            if (parts[x].Trim() == "")
                parts.RemoveAt(x);

        if (parts.Count > 0)
        {
            // Might want to add more to this list
            string[] prefixes = { "mr", "mrs", "ms", "dr", "miss", "sir", "madam", "mayor", "president" };

            // If first part is a prefix, set prefix and remove part
            string normalizedPart = parts.First().Replace(".", "").Replace(",", "").Trim().ToLower();
            if (prefixes.Contains(normalizedPart))
            {
                prefix = parts[0].Trim();
                parts.RemoveAt(0);
            }
        }

        if (parts.Count > 0)
        {
            // Might want to add more to this list, or use code/regex for roman-numeral detection
            string[] suffixes = { "jr", "sr", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", "xi", "xii", "xiii", "xiv", "xv" };

            // If last part is a suffix, set suffix and remove part
            string normalizedPart = parts.Last().Replace(".", "").Replace(",", "").Trim().ToLower();
            if (suffixes.Contains(normalizedPart))
            {
                suffix = parts.Last().Replace(",", "").Trim();
                parts.RemoveAt(parts.Count - 1);
            }
        }

        // Done, if no more parts
        if (parts.Count == 0)
            return;

        // If only one part left...
        if (parts.Count == 1)
        {
            // If no prefix, assume first name, otherwise last
            // i.e.- "Dr Jones", "Ms Jones" -- likely to be last
            if(prefix == "")
                first = parts.First().Replace(",", "").Trim();
            else
                last = parts.First().Replace(",", "").Trim();
        }

        // If first part ends with a comma, assume format:
        //   Last, First [...First...]
        else if (parts.First().EndsWith(","))
        {
            last = parts.First().Replace(",", "").Trim();
            for (int x = 1; x < parts.Count; x++)
                first += parts[x].Replace(",", "").Trim() + " ";
            first = first.Trim();
        }

        // Otherwise assume format:
        // First [...Middle...] Last

        else
        {
            first = parts.First().Replace(",", "").Trim();
            last = parts.Last().Replace(",", "").Trim();
            for (int x = 1; x < parts.Count - 1; x++)
                middle += parts[x].Replace(",", "").Trim() + " ";
            middle = middle.Trim();
        }
    }

Извините, что код длинный и уродливый, я не стал его чистить. Это расширение С#, поэтому вы должны использовать его как:

string name = "Miss Jessica Dark-Angel Alba";
string prefix, first, middle, last, suffix;
name.ParseName(out prefix, out first, out middle, out last, out suffix);

Ответ 4

Вам, вероятно, не нужно ничего делать. Что-то вроде этого должно работать.

    Name = Name.Trim();

    arrNames = Name.Split(' ');

    if (arrNames.Length > 0) {
        GivenName = arrNames[0];
    }
    if (arrNames.Length > 1) {
        FamilyName = arrNames[arrNames.Length - 1];
    }
    if (arrNames.Length > 2) {
        MiddleName = string.Join(" ", arrNames, 1, arrNames.Length - 2);
    }

Вы также можете сначала проверить заголовки.

Ответ 5

Я должен был это сделать. На самом деле, что-то гораздо сложнее, потому что иногда "имя" было бы "Смит, Джон" или "Смит Джон" вместо "Джон Смит" или вообще не имя человека, а вместо имени компании. И он должен был сделать это автоматически без возможности для пользователя исправить его.

То, что я закончил, - это придумать конечный список шаблонов, в которых может быть имя, например:
Последнее, первое начальное начальное
Первый последний
Первый средний начальный последний
Последний, первый средний
Первый средний последний
Первый Последний

Бросьте в своего мистера, младшего, там тоже. Скажем, вы закончили с дюжиной шаблонов.

В моем приложении был словарь общего имени, общих фамилий (вы можете найти их в Интернете), общие названия, общие суффиксы (jr, sr, md), и с помощью этого можно было бы сделать хорошие догадки о шаблоны. Я не такой умный, моя логика не была такой фантазией, и тем не менее, было не так сложно создать какую-то логику, которая догадалась, что уже более 99% времени.

Ответ 6

Я ценю, что это трудно сделать правильно, но если вы предоставите пользователю способ редактировать результаты (скажем, всплывающее окно, чтобы изменить имя, если оно не догадалось, правильно) и догадываться "правильно" "для большинства случаев... конечно, это угадание, что трудно.

Легко сказать "не делай этого" при теоретическом рассмотрении проблемы, но иногда обстоятельства диктуют иначе. Области для всех частей имени (название, первый, средний, последний, суффикс, просто чтобы назвать несколько) могут занимать много экранной недвижимости - и в сочетании с проблемой адреса (тема для другого дня ) может действительно загромождать то, что должно быть чистым, простым пользовательским интерфейсом.

Я предполагаю, что ответ должен быть "не делайте этого, если вам это абсолютно не нужно, и если вы это сделаете, сохраните его просто (некоторые методы для этого были опубликованы здесь) и предоставляют пользователю средства для редактирования результатов, если необходимо".

Ответ 7

Понимая, что это плохая идея, я написал это регулярное выражение в perl - вот что сработало лучше для меня. Я уже отфильтровал названия компаний.
Вывод в формате vcard: (hon_prefix, given_name, дополнительное_имя, имя_пользователя, hon. Суффикс)

/^ \s*
    (?:((?:Dr.)|(?:Mr.)|(?:Mr?s.)|(?:Miss)|(?:2nd\sLt.)|(?:Sen\.?))\s+)? # prefix
    ((?:\w+)|(?:\w\.)) # first name
(?: \s+ ((?:\w\.?)|(?:\w\w+)) )?  # middle initial
(?: \s+ ((?:[OD]['’]\s?)?[-\w]+))    # last name
(?: ,? \s+ ( (?:[JS]r\.?) | (?:Esq\.?) | (?: (?:M)|(?:Ph)|(?:Ed) \.?\s*D\.?) | 
         (?: R\.?N\.?) | (?: I+) )  )? # suffix
\s* $/x

Примечания:

  • не обрабатывает IV, V, VI
  • Жестко закодированные списки префиксов, суффиксов. из набора данных из имен ~ 2K
  • Не обрабатывает несколько суффиксов (например, MD, PhD)
  • Предназначен для американских имен - не будет работать должным образом на латинированных японских именах или других системах именования.

Ответ 8

Реальное решение здесь не отвечает на вопрос. Должен соблюдаться характер информации. Имя не просто имя; это как мы знаем.

Проблема здесь не в том, чтобы точно знать, какие части имеют значение, и для чего они используются. Почетные префиксы должны предоставляться только в личных корыстных контактах; Доктор является почетным, который получен из названия. Вся информация о человеке связана с их личностью, это просто определение того, что является релевантной информацией. Вам необходимо указать имя и фамилию по причинам администрирования; номер телефона, адреса электронной почты, описания земель и почтовые адреса; все к знанию личности, зная, с кем вы имеете дело.

Реальная проблема здесь в том, что человек теряется в администрации. Внезапно, только вводя их личную информацию в форму и передавая ее на произвольную программу для обработки, им становится предоставлено всевозможное почетное звание и нравы, изгоняемые сборным шаблоном. Это не верно; уважаемый сэр или мадам, если личный интерес проявляется к причине коррозии, тогда письмо никогда не должно быть написано из шаблона. Личное совпадение требует небольшого знания о получателе. Муж или женщина, ходили в школу, чтобы быть врачом или судьей, в какой культуре они были воспитаны.

В других культурах имя составлено из переменного количества символов. Имя человека для нас может быть интерпретировано только как строка чисел, где пробелы фактически определяются шириной символа вместо символа пробела. Honorifics в этих случаях - это один или несколько символов, префикс и суффикс фактического имени. Вежливая вещь, которую нужно сделать, это использовать строку, которую вы даете, если вы знаете почетную, то, во что бы то ни стало ее используете, но это опять-таки подразумевает какие-то личные знания получателя. Вызов Сэнсэя не что иное, как Сенсей. Не в смысле логической ошибки, но в том, что вы только что оскорбили своего звонящего, и теперь вы должны найти шаблон, который поможет вам извиниться.

В целях автоматизированной безличной коррозии шаблон может быть разработан для таких вещей, как ежедневные статьи, еженедельные выпуски или что-то еще, но проблема становится важной, когда получатель получает автоматическую услугу.

Что происходит, это ошибка. Недостающая информация. Неизвестная или отсутствующая информация всегда генерирует исключение. Реальная проблема заключается не в том, как вы отделяете имя человека от своих отдельных компонентов с выражением, но как вы их называете.

Решение состоит в том, чтобы создать дополнительное поле, сделать его необязательным, если уже есть имя и фамилия, и называть его "Что мы можем вам назвать" или "Как мы должны обращаться к вам как". Врач и судья обеспечат вам правильное обращение к ним. Это не проблемы программирования, они являются проблемами связи.

Хорошо, это плохо, но, на мой взгляд, имя пользователя, тэг и идентификатор хуже. Итак, мое решение; это недостающий вопрос: "Что мы должны будем вам звонить?"

Это только решение, в котором вы можете позволить себе задать новый вопрос. Преобладает конфликт. Создайте новое поле в своих пользовательских формах, назовите его "Псевдоним", назовите для пользователя "Что мы должны вам звонить?", Тогда у вас есть средство для общения. Используйте имя и фамилию, если получатель не дал псевдоним или лично знаком с отправителем, тогда первый и средний будут приемлемыми.

To Me, _______________________ (standard subscribed corrospondence)
To Me ( Myself | I ), ________ (standard recipient instigated corrospondence)
To Me Myself I, ______________ (look out, its your mother, and you're in big trouble;
                                nobody addresses a person by their actual full name)

Dear *(Mr./Mrs./Ms./Dr./Hon./Sen.) Me M. I *(I),
To Whom it may Concern;

В противном случае вы ищете что-то стандартное: привет, привет, вы можете быть победителем.

Если у вас есть данные, являющиеся именем человека, все в одной строке, у вас нет проблемы, потому что у вас уже есть свой псевдоним. Если вам нужно первое и последнее имя, тогда просто Left (name, instr (name, ")) и" "и Right (name, instrrev (name," ")), моя математика, вероятно, неверна, немного из практики. сравните влево и вправо с известными префиксами и суффиксами и устраните их из своих совпадений. Обычно среднее имя используется редко, за исключением случаев подтверждения личности; который адрес или номер телефона говорит вам намного больше. Наблюдая за гифанизацией, можно определить, что если фамилия не используется, тогда вместо нее будет один из средних.

Для поиска списков имен и фамилий необходимо учитывать возможность использования одного из средних; для этого потребуется четыре поиска: один для фильтрации для первого и последнего, затем для фильтрации первого и среднего, затем другого для фильтрации среднего и последнего, а затем другого для фильтрации среднего и среднего. В конечном счете, первое имя всегда первое, а последнее всегда последнее, и может быть любое количество средних имен; меньше, и где нуль вероятен, но маловероятен.

Иногда люди предпочитают называться Билл, Гарри, Джим, Боб, Даг, Бет, Сью или Мадонна; чем их фактические имена; подобный, но нереалистично ожидаемый от любого, кто понимает все различные возможности.

Самая вежливая вещь, которую вы могли бы сделать, это спросить; Что мы можем вам назвать?

Ответ 9

Придя к этому разговору на 10 лет позже, но все еще в поисках элегантного решения, я прочитал эту ветку и решил пойти по пути, который выбрал @eselk, но подробно остановился на нем:

public class FullNameDTO
{
    public string Prefix     { get; set; }
    public string FirstName  { get; set; }
    public string MiddleName { get; set; }
    public string LastName   { get; set; }
    public string Suffix     { get; set; }
}

public static class FullName
{
    public static FullNameDTO GetFullNameDto(string fullName)
    {
        string[] knownPrefixes    = { "mr", "mrs", "ms", "miss", "dr", "sir", "madam", "master", "fr", "rev", "atty", "hon", "prof", "pres", "vp", "gov", "ofc" };
        string[] knownSuffixes    = { "jr", "sr", "ii", "iii", "iv", "v", "esq", "cpa", "dc", "dds", "vm", "jd", "md", "phd" };
        string[] lastNamePrefixes = { "da", "de", "del", "dos", "el", "la", "st", "van", "von" };

        var prefix     = string.Empty;
        var firstName  = string.Empty;
        var middleName = string.Empty;
        var lastName   = string.Empty;
        var suffix     = string.Empty;

        var fullNameDto = new FullNameDTO
        {
            Prefix     = prefix,
            FirstName  = firstName,
            MiddleName = middleName,
            LastName   = lastName,
            Suffix     = suffix
        };

        // Split on period, commas or spaces, but don't remove from results.
        var namePartsList = Regex.Split(fullName, "(?<=[., ])").ToList();

        #region Clean out the crap.
        for (var x = namePartsList.Count - 1; x >= 0; x--)
        {
            if (namePartsList[x].Trim() == string.Empty)
            {
                namePartsList.RemoveAt(x);
            }
        }
        #endregion

        #region Trim all of the parts in the list
        for (var x = namePartsList.Count - 1; x >= 0; x--)
        {
            namePartsList[x] = namePartsList[x].Trim();
        }
        #endregion

        #region Only one Name Part - assume a name like "Cher"
        if (namePartsList.Count == 1)
        {
            firstName = namePartsList.First().Replace(",", string.Empty).Trim();
            fullNameDto.FirstName = firstName;

            namePartsList.RemoveAt(0);
        }
        #endregion

        #region Get the Prefix
        if (namePartsList.Count > 0)
        {
            //If we find a prefix, save it and drop it from the overall parts
            var cleanedPart = namePartsList.First()
                                           .Replace(".", string.Empty)
                                           .Replace(",", string.Empty)
                                           .Trim()
                                           .ToLower();

            if (knownPrefixes.Contains(cleanedPart))
            {
                prefix = namePartsList[0].Trim();
                fullNameDto.Prefix = prefix;

                namePartsList.RemoveAt(0);
            }
        }
        #endregion

        #region Get the Suffix
        if (namePartsList.Count > 0)
        {
            #region Scan the full parts list for a potential Suffix
            foreach (var namePart in namePartsList)
            {
                var cleanedPart = namePart.Replace(",", string.Empty)
                                          .Trim()
                                          .ToLower();

                if (!knownSuffixes.Contains(cleanedPart.Replace(".", string.Empty))) { continue; }

                if (namePart.ToLower() == "jr" && namePart != namePartsList.Last()) { continue; }

                suffix             = namePart.Replace(",", string.Empty).Trim();
                fullNameDto.Suffix = suffix;

                namePartsList.Remove(namePart);
                break;
            }
            #endregion
        }
        #endregion

        //If, strangely, there nothing else in the overall parts... we're done here.
        if (namePartsList.Count == 0) { return fullNameDto; }

        #region Prefix/Suffix taken care of - only one "part" left.
        if (namePartsList.Count == 1)
        {
            //If no prefix, assume first name (e.g. "Cher"), otherwise last (e.g. "Dr Jones", "Ms Jones")
            if (prefix == string.Empty)
            {
                firstName = namePartsList.First().Replace(",", string.Empty).Trim();
                fullNameDto.FirstName = firstName;
            }
            else
            {
                lastName = namePartsList.First().Replace(",", string.Empty).Trim();
                fullNameDto.LastName = lastName;
            }
        }
        #endregion

        #region First part ends with a comma
        else if (namePartsList.First().EndsWith(",") || (namePartsList.Count >= 3 && namePartsList.Any(n => n == ",") && namePartsList.Last() != ","))
        {
            #region Assume format: "Last, First"
            if (namePartsList.First().EndsWith(","))
            {
                lastName             = namePartsList.First().Replace(",", string.Empty).Trim();
                fullNameDto.LastName = lastName;
                namePartsList.Remove(namePartsList.First());

                firstName             = namePartsList.First();
                fullNameDto.FirstName = firstName;
                namePartsList.Remove(namePartsList.First());

                if (!namePartsList.Any()) { return fullNameDto; }

                foreach (var namePart in namePartsList)
                {
                    middleName += namePart.Trim() + " ";
                }
                fullNameDto.MiddleName = middleName;

                return fullNameDto;
            }
            #endregion

            #region Assume strange scenario like "Last Suffix, First"
            var indexOfComma = namePartsList.IndexOf(",");

            #region Last Name is the first thing in the list
            if (indexOfComma == 1)
            {
                namePartsList.Remove(namePartsList[indexOfComma]);

                lastName             = namePartsList.First().Replace(",", string.Empty).Trim();
                fullNameDto.LastName = lastName;
                namePartsList.Remove(namePartsList.First());

                firstName             = namePartsList.First();
                fullNameDto.FirstName = firstName;
                namePartsList.Remove(namePartsList.First());

                if (!namePartsList.Any()) { return fullNameDto; }

                foreach (var namePart in namePartsList)
                {
                    middleName += namePart.Trim() + " ";
                }
                fullNameDto.MiddleName = middleName;

                return fullNameDto;
            }
            #endregion

            #region Last Name might be a prefixed one, like "da Vinci"
            if (indexOfComma == 2)
            {
                var possibleLastPrefix = namePartsList.First()
                                                      .Replace(".", string.Empty)
                                                      .Replace(",", string.Empty)
                                                      .Trim()
                                                      .ToLower();

                if (lastNamePrefixes.Contains(possibleLastPrefix))
                {
                    namePartsList.Remove(namePartsList[indexOfComma]);

                    var lastPrefix = namePartsList.First().Trim();
                    namePartsList.Remove(lastPrefix);

                    lastName             = $"{lastPrefix} {namePartsList.First().Replace(",", string.Empty).Trim()}";
                    fullNameDto.LastName = lastName;
                    namePartsList.Remove(namePartsList.First());
                }
                else
                {
                    lastName = namePartsList.First().Replace(",", string.Empty).Trim();
                    namePartsList.Remove(namePartsList.First());

                    lastName = lastName + " " + namePartsList.First().Replace(",", string.Empty).Trim();
                    namePartsList.Remove(namePartsList.First());

                    fullNameDto.LastName = lastName;
                }

                namePartsList.Remove(",");

                firstName             = namePartsList.First();
                fullNameDto.FirstName = firstName;
                namePartsList.Remove(namePartsList.First());

                if (!namePartsList.Any()) { return fullNameDto; }

                foreach (var namePart in namePartsList)
                {
                    middleName += namePart.Trim() + " ";
                }
                fullNameDto.MiddleName = middleName;

                return fullNameDto;
            }
            #endregion
            #endregion
        }
        #endregion

        #region Everything else
        else
        {
            if (namePartsList.Count >= 3)
            {
                firstName = namePartsList.First().Replace(",", string.Empty).Trim();
                fullNameDto.FirstName = firstName;
                namePartsList.RemoveAt(0);

                //Check for possible last name prefix

                var possibleLastPrefix = namePartsList[namePartsList.Count - 2]
                                               .Replace(".", string.Empty)
                                               .Replace(",", string.Empty)
                                               .Trim()
                                               .ToLower();

                if (lastNamePrefixes.Contains(possibleLastPrefix))
                {
                    lastName = $"{namePartsList[namePartsList.Count - 2].Trim()} {namePartsList[namePartsList.Count -1].Replace(",", string.Empty).Trim()}";
                    fullNameDto.LastName = lastName;

                    namePartsList.RemoveAt(namePartsList.Count - 1);
                    namePartsList.RemoveAt(namePartsList.Count - 1);
                }
                else
                {
                    lastName = namePartsList.Last().Replace(",", string.Empty).Trim();
                    fullNameDto.LastName = lastName;

                    namePartsList.RemoveAt(namePartsList.Count - 1);
                }

                middleName = string.Join(" ", namePartsList).Trim();
                fullNameDto.MiddleName = middleName;

                namePartsList.Clear();
            }
            else
            {
                if (namePartsList.Count == 1)
                {
                    lastName = namePartsList.First().Replace(",", string.Empty).Trim();
                    fullNameDto.LastName = lastName;

                    namePartsList.RemoveAt(0);
                }
                else
                {
                    var possibleLastPrefix = namePartsList.First()
                                             .Replace(".", string.Empty)
                                             .Replace(",", string.Empty)
                                             .Trim()
                                             .ToLower();

                    if (lastNamePrefixes.Contains(possibleLastPrefix))
                    {
                        lastName = $"{namePartsList.First().Replace(",", string.Empty).Trim()} {namePartsList.Last().Replace(",", string.Empty).Trim()}";
                        fullNameDto.LastName = lastName;

                        namePartsList.Clear();
                    }
                    else
                    {
                        firstName = namePartsList.First().Replace(",", string.Empty).Trim();
                        fullNameDto.FirstName = firstName;

                        namePartsList.RemoveAt(0);

                        lastName = namePartsList.Last().Replace(",", string.Empty).Trim();
                        fullNameDto.LastName = lastName;

                        namePartsList.Clear();
                    }
                }
            }
        }
        #endregion

        namePartsList.Clear();

        fullNameDto.Prefix     = prefix;
        fullNameDto.FirstName  = firstName;
        fullNameDto.MiddleName = middleName;
        fullNameDto.LastName   = lastName;
        fullNameDto.Suffix     = suffix;

        return fullNameDto;
    }
}

Это будет обрабатывать несколько различных сценариев, и я написал (пока) более 50 различных модульных тестов, чтобы убедиться в этом.

Снова обращайтесь к @eselk за его идеями, которые помогли мне написать расширенную версию его превосходного решения. И, в качестве бонуса, это также обрабатывает странный случай человека по имени "JR".

Ответ 10

В нашей компании есть несколько надстроек, которые мы использовали для этой цели. В итоге я создал способ фактического определения форматов имени для разных клиентов для разных клиентов. Есть компания, у которой есть инструмент, который по моему опыту стоит того, и он действительно невероятен при решении этой темы. Он по адресу: http://www.softwarecompany.com/ и отлично работает. Самый эффективный способ сделать это с помощью любого статистического подхода состоит в том, чтобы разбить строку запятыми или пробелами, затем: 1. разделите заголовки и префиксы на 2. разделите суффиксы на 3, проанализируйте имя в порядке (2 имени = F и L, 3 имени = FML или LMF) в зависимости от порядка строки().

Ответ 11

Вы можете делать очевидные вещи: искать младших, II, III и т.д. в качестве суффиксов, а г-н, г-жа, д-р и т.д. в качестве префиксов и удалять их, тогда первое слово - это имя, последнее слово - фамилия, все между ними - это средние имена. Кроме этого, для этого нет надежного решения.

Прекрасным примером является Дэвид Ли Рот (фамилия: Рот) и Эдди Ван Хален (фамилия: Ван Хален). Если имя Энн Мэри Смит - "Энн Мари", нет никакого способа отличить это от Энн, имеющего второе имя Мари.

Ответ 12

Если вам просто нужно это сделать, добавьте угадывания в пользовательский интерфейс как дополнительный выбор. Таким образом, вы могли бы рассказать пользователю, как вы анализировали имя и позволяете им выбирать другой синтаксический анализ из списка, который вы предоставляете.

Ответ 13

Существует сторонний инструмент для такого рода продуктов, который называется NetGender, который работает на удивление хорошо. Я использовал его для синтаксического анализа огромного количества действительно неправильных имен в непредсказуемых форматах. Взгляните на примеры на своей странице, и вы также можете скачать и попробовать.

http://www.softwarecompany.com/dotnet/netgender.htm

Я придумал эту статистику на основе выборки из 4,2 млн. имен. Название Parts означает количество отдельных частей, разделенных пробелами. Очень большой процент был правильным для большинства имен в базе данных. Правильность уменьшилась, поскольку части поднялись, но было очень мало имен s > 3 частями и меньше s > 4. Это было достаточно хорошо для нашего дела. Там, где упало программное обеспечение, были обнаружены неизвестные имена нескольких частей, даже если они разделены запятой. Если бы он смог расшифровать это, то общее количество ошибок было бы менее 1% для всех данных.

Name Parts | Correct | Percent of Names in DB
 2             100%       48%
 3              98%       42%
 4              70%        9%
 5              45%        0.25%

Ответ 14

Я уже делаю эту серверную загрузку на странице. Написал ColdFusion CFC, который передал ему два параметра - фактические данные пользователя (имя, отчество, фамилия) и тип данных (первый, средний, последний). Затем выполняются обычные проверки дефисов, апострофов, пробелов и форматов. ех. Макдональд, МакМюррей, О'Нил, Родэм-Клинтон, Эрик фон Голланд, Дж. У. Буш, Джек Бертон-младший, Д-р Пол Окин, Крис ди Сантос. В случае, когда у пользователей есть только одно имя, требуется только поле первого имени, а также фамилии и фамилии необязательны.

Вся информация хранится в нижнем регистре - кроме префикса, суффикса и пользовательского. Это форматирование выполняется при рендеринге страницы, а не во время хранения в db. Хотя есть фильтрация проверки, когда пользователь вводит данные. Извините, не могу отправить код. Начал использовать Regex, но стал слишком запутанным и ненадежным для всех сценариев. Используемые стандартные логические блоки (if/else, switch/case), легче читать и отлаживать. СДЕЛАЙТЕ КАЖДОЙ ВХОД/ПОЛЕ БАНКА ОТДЕЛЬНО! Да, это займет некоторое кодирование, но после того, как вы закончите, он должен учитывать 99% комбинаций. Только на основе английских имен до сих пор не интернационализация, это еще один воск.

Вот некоторые вещи, которые следует учитывать:

  • Hypens (например, Rodham-Clinton, может быть в первом, среднем или последнем)
  • Апострофы (например, О'Нил, могут быть в первом, среднем или последнем)
  • Пробелы
  • Mc и Mac (например, McDonald, MacMurray, могут быть в первом, среднем или
    последний)
  • Имена: несколько первых имен (например, Joe Bob Briggs)
  • Фамилии: de, di, et, der, den, van, von, af должны быть строчными (ex Eric фон Дандер, Мэри-ди-Карло)
  • Префикс: Dr., Prof. и т.д.
  • Суффикс: Jr., Sr., Esq., II, III и т.д.

Когда пользователь вводит информацию, схема поля в db выглядит так:

  • Префикс/Название (д-р и т.д. с помощью раскрывающегося списка)
  • Префикс/Название Пользовательский (пользователь может ввести пользовательский, например, Capt. с использованием текста поле)
  • Имя
  • Средний
  • Фамилия
  • Суффикс (Jr., III, Prof., Ret. и т.д., используя раскрывающийся список)
  • Suffix Custom (пользователь может ввести пользовательскую, например, CPA)

Здесь одно Regex, которое я использую, чтобы сделать первую букву каждого имени в верхнем регистре. Я запускаю это сначала, а затем подпрограммирует формат в соответствии с правилами (он в формате Coldfusion, но вы получаете идею):

<cfset var nameString = REReplace(LCase(nameString), "(^[[:alpha:]]|[[:blank:]][[:alpha:]])", "\U\1\E", "ALL")>

Вы также можете сделать эту клиентскую часть с использованием JavaScript и CSS - возможно, даже проще, но я предпочитаю делать серверную часть, так как мне нужны переменные, установленные до загрузки страницы на стороне клиента.

Ответ 15

Я бы сказал, вырезать приветствия из списка, затем разделить по пробелу, поместив list.first() в качестве имени, list.last() в качестве имени, затем присоедините остаток к пробелу и получите это как среднее имя. И ВЫШЕ ВСЕ отображают ваши результаты и позволяют пользователю изменять их!

Ответ 16

Конечно, есть простое решение - разделите строку пробелами, подсчитайте количество токенов, если их 2, интерпретируйте их как FIRST и LAST, если их 3, интерпретируйте их как FIRST, MIDDLE, и LAST.

Проблема в том, что простое решение не будет 100% правильным решением - кто-то всегда может вводить имя со многими другими токенами или может включать в себя названия, фамилии с пробелом в нем (возможно ли это?) и т.д. Вы можете найти решение, которое работает для большинства имен большую часть времени, но не является абсолютным решением.

Я бы воспользовался рекомендацией Шада по разделению полей ввода.

Ответ 17

Вы не хотите этого делать, если только вы не свяжетесь с людьми из одной культуры.

Например:

Гвидо ван Россум фамилия ван Россум.

Имя MIYAZAKI Hayao - Hayao.

Самый успешный результат, который вы могли бы сделать, это отменить общие заголовки и приветствия и попробовать некоторые эвристики.

Тем не менее, самым простым решением является просто сохранить полное имя или запросить имя и фамилию отдельно.

Ответ 18

Это безумное поручение. Слишком много исключений, чтобы иметь возможность сделать это детерминистически. Если бы вы делали это, чтобы предварительно обработать список для дальнейшего рассмотрения, я бы утверждал, что меньше, конечно, будет больше.

  • Разделите приветствия, заголовки и суффиксы генерации (большое регулярное выражение или несколько небольших).
  • если только одно имя, оно является "последним".
  • Если только два имени разделили их на первый, последний.
  • Если три токена и средний - это начальный, разделите их на первый, средний, последний
  • Сортировка остальных вручную.

Любая дальнейшая обработка почти гарантированно создаст больше работы, так как вам придется пройти рекомбинацию, разделяющую вашу обработку.

Ответ 19

Я согласен, для этого нет простого решения. Но я нашел ужасный подход в статье Microsoft KB для VB 5.0, которая является реальной реализацией для большей части обсуждаемого здесь обсуждения: http://support.microsoft.com/kb/168799

Что-то вроде этого можно было бы использовать в крайнем случае.

Ответ 20

Существует 100% -ный способ сделать это.

Вы можете разделить на пробелы и попытаться понять имя, которое хотите, но когда дело доходит до него, вы иногда ошибетесь. Если это достаточно хорошо, пойдите для любого из ответов здесь, которые дают вам способы разделить.

Но у некоторых людей будет такое имя, как "Джон Уэйн Олсон", где "Джон Уэйн" - это первое имя, а у кого-то будет такое имя, как "Джон Уэйн Олсон", где "Уэйн" - их второе имя. В этом имени нет ничего присутствующего, который расскажет вам, каким образом его интерпретировать.

Это так, как есть. Это аналоговый мир.

Мои правила довольно просты.

Возьмите последнюю часть → Фамилия
Если осталось несколько частей, возьмите последнюю часть → Среднее имя
Что осталось → Имя

Но не предполагайте, что это будет на 100% точным, и не будет любого другого жестко запрограммированного решения. Вам нужно будет позволить пользователю отредактировать его сам.

Ответ 21

Я сделал что-то подобное. Основная проблема, с которой я столкнулся, заключалась в том, что люди вводили такие вещи, как "Ричард Р. Смит-младший" Я отправил свой код в http://www.blackbeltcoder.com/Articles/strings/splitting-a-name-into-first-and-last-names. Он в С#, но может быть легко преобразован в VB.

Ответ 22

Я согласен с не делать этого. Название Rick Van DenBoer получило бы второе имя Van, но оно было частью фамилии.