preg_match группы соответствия имени / фамилии

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

$success = preg_match("/([\x{00c0}-\x{01ff}a-zA-Z'-]){2,}(\s([\x{00c0}-\x{01ff}a-zA-Z'-]{1,})*)?\s([\x{00c0}-\x{01ff}a-zA-Z'-]{2,})/ui",$user['name'],$matches);

$output[($success ? 'hits' : 'misses')][] = ['id' => $user['id'],'email' => $user['email'],'name' => $user['name'],'matches' => $matches];

Кажется, работает нормально с точки зрения попаданий / промахов, то есть истина / ложь, независимо от того, соответствует он или нет.

Но затем я пытаюсь использовать то же самое, чтобы извлечь имя и фамилию, используя группы, которые я изо всех сил пытаюсь получить право..

Получить много результатов, таких как:

  "name": "Jonny Nott",
  "matches": [
    "Jonny Nott",
    "y",
    "",
    "",
    "Nott"
  ]

  "name": "Name Here",
  "matches": [
    "Name Here",
    "e",
    "",
    "",
    "Here"
  ]

  "matches": [
    "Jonathan M Notty",
    "n",
    " M",
    "M",
    "Notty"
  ]

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

Любые указатели относительно того, что не так?

3 ответа

Решение

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

  • Оптимизируйте схему и избавьтесь от избыточных групп (например, групп вокруг отдельных атомов - (a)+ => a+)
  • Превратить группы захвата в без захвата ((\s+\w+)+ => (?:\s+\w+)+)

Кроме того, в вашем случае вы можете улучшить шаблон, если вы замените часть, соответствующую букве, на \p{L} Класс свойств Unicode, который соответствует любым буквам.

использование

/[\p{L}'-]{2,}(?:\s[\p{L}'-]+)?\s[\p{L}'-]{2,}/u

Посмотреть демо-версию регулярного выражения

Здесь осталась только одна группировка, (?:...)и это необязательно, ? после того, как это делает это соответствует 1 или 0 раз.

подробности

  • [\p{L}'-]{2,} - 2 или более букв, ' или же -
  • (?:\s[\p{L}'-]+)? - 1 или 0 вхождений пробела, а затем 1 или более букв, ' или же -
  • \s - пробел
  • [\p{L}'-]{2,} - 2 или более букв, ' или же -

Пытаться:

(?P<firstName>[\x{00c0}-\x{01ff}a-zA-Z'-]{2,})(\s([\x{00c0}-\x{01ff}a-zA-Z'-]{1,})*)?\s(?P<lastName>[\x{00c0}-\x{01ff}a-zA-Z'-]{2,})

Главная ошибка, которую вы повторили, первая группа {2,} - не первый диапазон

Используйте группы без захвата (?:...) всякий раз, когда вам нужно использовать круглые скобки, но вы не хотите сопоставлять эту часть (например, часть пробелов и отчество) и включать квантификатор в группу захвата, а не только символы для сопоставления (например, для имени {2,} должен быть в группе захвата).

([\x{00c0}-\x{01ff}a-zA-Z'-]{2,})(?:\s(?:[\x{00c0}-\x{01ff}a-zA-Z'-]{1,})*)?\s([\x{00c0}-\x{01ff}a-zA-Z'-]{2,})
Другие вопросы по тегам