Как строку разобрать на ФИО, дату рождения и регион?

Есть строка такого типа:

Александрова Мария Николаевна 10.05.2000 197

Мне нужно из этой строки достать $lastname, $firstname, $secondname, $birthdate и $region.

Можно было бы использовать просто explode с разделительным пробелом, НО дело в том, что дня рождения и отчества может вообще не быть. То есть минимальный вид строки возможен такой

Александрова Мария 197

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


Ответы (2 шт):

Автор решения: Алексей Леонов

Как сказали выше, проверяем предпоследний элемент + считаем сколько элементов в массиве. Если предпоследний дата и всего 5 элементов, значит ФИО, если 4 элемента, значит Фамилия и Имя. Если предпоследний не дата и 4 элемента, то ФИО, если 3 элемента, то Фамилия и Имя

→ Ссылка
Автор решения: UModeL

Сразу оговорюсь, я не занимаюсь бэкэнд разработкой, потому не слежу за актуальностью версий PHP и охватом этими версиями серверов. Главное, что принцип неизменен.

Собственно, если объёмы данных небольшие, и не требуется сверхбыстродействие, то регулярное выражение вполне уместно. Для заявленных в вопросе условий, код будет таким:

<?php
// Регулярное выражение
$re = '/^(\S+)\s+([^\d\s]+)\s+(?:([^\d\s]+)\s+)?(?:([\d.]+)\s+)?(\d+)$/im';
// Исходная строка
$str = 'Александрова Мария Николаевна 10.05.2000 197';
// Поиск совпадений
preg_match($re, $str, $matches);
// Если совпадения найдены, тогда...
if ($matches) {
    // Распределение значений массива совпадений в переменные
    list(,$lastname, $firstname, $secondname, $birthdate, $region) = $matches;
    // Вывод
    echo "Фамилия: {$lastname}<br>\nИмя: {$firstname}<br>\nОтчество: " . ($secondname ?: 'не указано') . "<br>\nДата рождения: " . ($birthdate ?: 'не указана') . "<br>\nРегион: {$region}<hr>";
// иначе   
} else {
    // "Зануляем" значения переменных
    $lastname = $firstname = $secondname = $birthdate = $region = null;
    // Выводим предупреждение
    echo "Количество данных недостаточно для отображения<hr>";
}
?>

Для многострочных данных (PHP 7.1.0 и выше):

<?php
// Регулярное выражение
$re = '/^(?<lastname>\S+)\s+(?<firstname>[^\d\s]+)\s+(?:(?<secondname>[^\d\s]+)\s+)?(?:(?<birthdate>[\d.]+)\s+)?(?<region>\d+)$/im';
/* Исходная строка
1) Фамилия, Имя, Отчество, Дата, Регион +
2) Фамилия, Имя, Отчество, Регион       +
3) Фамилия, Имя, Дата, Регион +
4) Фамилия, Имя, Регион       +
5) Фамилия, Дата, Регион -
6) Фамилия, Регион       -
*/
$str = '
Александрова Мария Николаевна 10.05.2000 197
Александрова Мария Николаевна 197
Александрова Мария 10.05.2000 197
Александрова Мария 197
Александрова 10.05.2000 197
Александрова 197';
// Поиск всех совпадений
preg_match_all($re, $str, $matches);
// Деструктуризация в переменные
['lastname' => $lastname, 'firstname' => $firstname, 'secondname' => $secondname, 'birthdate' => $birthdate, 'region' => $region] = $matches;
// Количество строк
$count = count($matches[0]);
// Перебор массивов
for ($i = 0; $i < $count; $i++) {
    // Вывод
    echo "Фамилия: {$lastname[$i]}<br>\nИмя: {$firstname[$i]}<br>\nОтчество: " . ($secondname[$i] ?: 'не указано') . "<br>\nДата рождения: " . ($birthdate[$i] ?: 'не указана') . "<br>\nРегион: {$region[$i]}<hr>\n\n";
}
?>
→ Ссылка