@tatarrr95

Как вытащить дату из текста?

Пишу робота, который распознает речь. Робот спрашивает человека дату рождения, нужно ее распознать. Фразы могут быть такими:
"Я родился 2 июня 1745" (02.06.1745)
"дата 3 февраля 94" (03.02.1994)
"24 0 5 1996" (24.05.1996)
"0 6 12 78" (06.12.1978)
"7 8 94" (07.08.1994)
Есть ли какие-нибудь готовые решения для данной задачи? Думаю здесь можно легко обойтись без нейросетей. Естественно вопрос в том, как из обработанной текстовой строки достать дату, а не перевести, распознать речь и т.д.
  • Вопрос задан
  • 216 просмотров
Решения вопроса 1
@tatarrr95 Автор вопроса
Написал функцию php, решающую мою задачу без нейросетей. Существуют варианты дат, которые невозможно распознать однозначно, тогда возвращается два варианта даты.

function dateBirth($inputString){
            $inputString = str_replace(" январ", " 01", $inputString);
            $inputString = str_replace(" феврал", " 02", $inputString);
            $inputString = str_replace(" март", " 03", $inputString);
            $inputString = str_replace(" апрел", " 04", $inputString);
            $inputString = str_replace(" май", " 05", $inputString);
            $inputString = str_replace(" мая", " 05", $inputString);
            $inputString = str_replace(" мае", " 05", $inputString);
            $inputString = str_replace(" июн", " 06", $inputString);
            $inputString = str_replace(" июл", " 07", $inputString);
            $inputString = str_replace(" август", " 08", $inputString);
            $inputString = str_replace(" сентябр", " 09", $inputString);
            $inputString = str_replace(" октабр", " 10", $inputString);
            $inputString = str_replace(" ноябр", " 11", $inputString);
            $inputString = str_replace(" декабр", " 12", $inputString);
            $inputString = preg_replace('/\D/', '', $inputString);
            $year = "error";
            $daymonth = "";
            // Если длина строки больше 8 или меньше 4, вычислить дату не сможем
            if(strlen($inputString) < 4 || strlen($inputString) > 8){
                return false;
                
            }
            if(strlen($inputString) >= 6){ // если длина больше или равна 6, то год равен 4 числам
                if(intval(substr($inputString, -4)) > 1920){ //4 последних числа должны быть больше 1920, иначе это не год
                    $year = substr($inputString, -4);
                    $daymonth = substr($inputString, 0, -4);
                }
                if(strlen($inputString) == 6){ //если прошлое не год, значит год состоит из двух чисел, но тогда длина все строки не может быть длинее 6
                    if(intval("19".substr($inputString, -2)) > 1920){ //Проверяем, больше ли эти два числа чем 1920
                        $year = "19".substr($inputString, -2);
                        $daymonth = substr($inputString, 0, -2);
                    }
                }
            }
            else{
                if(intval("19".substr($inputString, -2)) > 1920){ //Если длина меньше 6, значит год из двух числел
                    $year = "19".substr($inputString, -2); //проверяем, больше ли год чем 1920
                    $daymonth = substr($inputString, 0, -2);
                }
            }
            // ищем день и месяц
            if($year != "error"){
                if(strlen($daymonth) == 4 || strlen($daymonth) == 2){ //если деньмесяц состоит из 2 или 4 чисел. бьем строку пополам и получаем день + месяц
                    $day = substr($daymonth, 0, -strlen($daymonth)/2);
                    $month = substr($daymonth, -strlen($daymonth)/2);
                }
                // Если деньмесяц состоит из 3 чисел, то сложно
                if(strlen($daymonth) == 3){
                    // Если первый 0, то день полюбому состоит из двух цифр
                    if(substr($daymonth, 0, 1) == "0"){ 
                        $day = substr($daymonth, 0, 2);
                        $month = substr($daymonth, -1);
                    }
                    // Если по середине 0, 1, 2 , то поулучается вилка, возвращаем сразу 2 вариианта
                    else if(substr($daymonth, 1, 1) == "0" || substr($daymonth, 1, 1) == "1" || substr($daymonth, 1, 1) == "2"){
                        $day = [substr($daymonth, 0, 1), substr($daymonth, 0, 2)]; //массив двух варантов дней
                        $month = [substr($daymonth, 1, 2), substr($daymonth, 2, 1)]; //массив двух вариантов месяцев
                        // проверяем, корректные ли дни и месяцы в массиве. Если нет, то превращаем массивы в немассивы без некорректных данных. Чтобы этим способом не проверить немассив, проверяем, массив ли это
                        if((intval($day[0]) > 31 || intval($month[0]) > 12 || intval($day[0]) == 0 || intval($month[0]) == 0) && is_array($day) && is_array($month)){
                            $day = $day[1];
                            $month = $month[1];
                        }
                        if((intval($day[1]) > 31 || intval($month[1]) > 12 || intval($day[1]) == 0 || intval($month[1]) == 0) && is_array($day) && is_array($month)){
                            $day = $day[0];
                            $month = $month[0];
                        }
                    }
                    // Если по середине 3
                    else if(substr($daymonth, 1, 1) == "3" && (substr($daymonth, 2, 1) == "1" || substr($daymonth, 2, 1) == "0")){
                        $day = [substr($daymonth, 0, 1), substr($daymonth, 0, 2)]; //массив двух варантов дней
                        $month = [substr($daymonth, 1, 2), substr($daymonth, 2, 1)]; //массив двух вариантов месяцев
                        // проверяем, корректные ли дни и месяцы в массиве. Если нет, то превращаем массивы в немассивы без некорректных данных. Чтобы этим способом не проверить немассив, проверяем, массив ли это
                        if((intval($day[0]) > 31 || intval($month[0]) > 12 || intval($day[0]) == 0 || intval($month[0]) == 0) && is_array($day) && is_array($month)){
                            $day = $day[1];
                            $month = $month[1];
                        }
                        if((intval($day[1]) > 31 || intval($month[1]) > 12 || intval($day[1]) == 0 || intval($month[1]) == 0) && is_array($day) && is_array($month)){
                            $day = $day[0];
                            $month = $month[0];
                        }
                    }
                    // Теперь просто двигаем точку с одного места ну другое проверяя, меньше ли день 31 и месяц 12. Если попали то круть
                    else{
                        // проверяем корректность данных при передвижении
                        if(intval(substr($daymonth, 0, 2)) <= 31 && intval(substr($daymonth, 0, 2)) != 0){
                            $day = substr($daymonth, 0, 2);
                            $month = substr($daymonth, -1);
                        }
                        // проверяем корректность данных при передвижении
                        else if(intval(substr($daymonth, 1, 2)) <= 12 && intval(substr($daymonth, 1, 2)) != 0 ){
                            $day = substr($daymonth, 0, 1);
                            $month = substr($daymonth, 1, 2);
                        }
                        else{
                            $day = "error";
                            $month = "error";
                        }
                    }

                }
            }
            $dataBorn = "";
            $format = 'd.m.Y';
            // Если в итоге у нас вернулось 2 варианта даты, работаем с ним
            if(is_array($day) && is_array($month)){
                $dataBorn = [$day[0].".".$month[0].".".$year , $day[1].".".$month[1].".".$year];
                $date = [];
                // пробуем законвертить дату и добавиить в массив, если не получается, значит хуевая дата
                try{
                    array_push($date, date_create_from_format($format, $dataBorn[0])->format('d.m.Y'));
                    // дополнительно проверяем на ошибки дату Например при конвертациии раньше 31.02.2016 выдавал не ошибку а 02.03.2016
                    if(DateTime::getLastErrors()['warning_count'] > 0) {
                        $date = "error";
                    }
                }
                catch (Error $e) {
                    $date = "error";
                }
                // пробуем законвертить дату и добавиить в массив, если не получается, значит хуевая дата
                try{
                    array_push($date, date_create_from_format($format, $dataBorn[1])->format('d.m.Y'));
                    // дополнительно проверяем на ошибки дату Например при конвертациии раньше 31.02.2016 выдавал не ошибку а 02.03.2016
                    if(DateTime::getLastErrors()['warning_count'] > 0) {
                        $date = "error";
                    }
                }
                catch (Error $e) {
                    $date = "error";
                }
                // Проверяем, остался ли массив после предыдущих манипуляций, и если в нем всего одно значение, переделываем массив в строку
                if(is_array($date) && count($date) < 2){
                    $date = $date[0];
                }
                return $date;
            }
            // Если вернулась всего одна дата
            else{
                // Проверяем на корректность день месяц
                if(intval($day) > 31 || intval($month) > 12 || intval($day) == 0 || intval($month) == 0){
                    $day = "error";
                    $month = "error";
                }
                $dataBorn = $day.".".$month.".".$year;
                // Продуем законвертииться в дату, если не получиилось, хуевая дата
                try {
                    $date = date_create_from_format($format, $dataBorn)->format('d.m.Y');
                    // дополнительно проверяем на ошибки дату Например при конвертациии раньше 31.02.2016 выдавал не ошибку а 02.03.2016
                    if(DateTime::getLastErrors()['warning_count'] > 0) {
                        $date = "error";
                    }
                } 
                catch (Error $e) {
                    $date = "error";
                }
                return $date;
            }
        }


Использовать как
dateBirth("текст текст текст 29.6.95 текст")
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
solotony
@solotony
покоряю пик Балмера
распарсить синтаксически правильные даты - Carbon::parse

а распарсить

"Я родился 2 июня 1745" (02.06.1745)
"дата 3 февраля 94" (03.02.1994)
"24 0 5 1996" (24.05.1996)
"0 6 12 78" (06.12.1978)
"7 8 94" (07.08.1994)

без нейросети вряд-ли получится

зы

02/03/19 - это что ?
2 марта 2019 ?
3 февраля 2019 ?
19 марта 2002 ?
а 02-03-19
Ответ написан
Комментировать
@Randewoo
Да уж, тут явно понадобятся нейросети!
Обратитесь к Бауманским студентам, может, кто-то подшабить захочет и возьмется за заказ.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы