Загрузка данных


// Функция принимает на вход сырой текст из файла и возвращает Массив Структур с разобранными данными.
// Требует платформу 1С не ниже 8.3.23!
Функция РаспарситьТекстБилетовНативно(Знач ТекстБилетов) Экспорт
    
    Результат = Новый Массив;
    
    // 1. Очистка от экранирующих кавычек
    ТекстБилетов = СтрЗаменить(ТекстБилетов, """", "");
    
    // 2. Разбиваем текст на строки и склеиваем "разорванные" записи
    МассивСырыхСтрок = СтрРазделить(ТекстБилетов, Символы.ПС, Ложь);
    МассивСтрок = Новый Массив;
    
    // Компилируем основные регулярные выражения один раз (флаг (?i) делает их нечувствительными к регистру)
    РегВырНачало       = Новый РегулярноеВыражение("(?i)^(Авиабилет|Электронный|Ж/д|Автобусный|Сверхнормативный|Доплата|а/б)");
    РегВырТип          = Новый РегулярноеВыражение("(?i)^(Авиабилет|Электронный ж/д билет|Ж/д билет|Автобусный билет|Сверхнормативный багаж[^(]*|Доплата за обмен[^(]*|а/б)");
    РегВырПеревозчик   = Новый РегулярноеВыражение("(?i)\(\s*перевозчик\s*(.*?)(?:,\s*ИНН\s*(\d*))?\s*\)");
    РегВырКласс        = Новый РегулярноеВыражение("(?i)\((Эконом|Купе|Плацкарт|Сидячий)\)");
    РегВырДата         = Новый РегулярноеВыражение("(?i)(\d{2}\.\d{2}\.\d{4}(?:\/\d{2}\.\d{2}\.\d{4})?)");
    РегВырПассажир     = Новый РегулярноеВыражение("(?i)\s+([А-Яа-яЁёA-Za-z\-]+\s+[А-Яа-яЁёA-Za-z]+\s+[А-Яа-яЁёA-Za-z]+|[А-Яа-яЁёA-Za-z\-]+\s+[А-Яа-яЁёA-Za-z]\.?\s*[А-Яа-яЁёA-Za-z]\.?\.?)$");
    РегВырНомерМаршрут = Новый РегулярноеВыражение("(?i)^([A-Za-z0-9\s/\.]+?)\s+([А-Яа-яЁёA-Za-z].*)$");
    
    Для Каждого Стр Из МассивСырыхСтрок Цикл
        СтрОчищ = СокрЛП(Стр);
        Если ПустаяСтрока(СтрОчищ) Тогда 
            Продолжить; 
        КонецЕсли;
        
        Если РегВырНачало.Совпадает(СтрОчищ) Тогда
            // Это начало нового билета
            МассивСтрок.Добавить(СтрОчищ);
        Иначе
            // Это продолжение предыдущей строки (например, перенос имени/проекта на новую строку)
            Если МассивСтрок.Количество() > 0 Тогда
                ИндексПоследней = МассивСтрок.ВГраница();
                МассивСтрок[ИндексПоследней] = МассивСтрок[ИндексПоследней] + " " + СтрОчищ;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    Для Каждого СтрокаБилета Из МассивСтрок Цикл
        
        ДанныеБилета = Новый Структура;
        ДанныеБилета.Вставить("ТипБилета", "");
        ДанныеБилета.Вставить("Перевозчик", "");
        ДанныеБилета.Вставить("ИНН", "");
        ДанныеБилета.Вставить("НомерБилета", "");
        ДанныеБилета.Вставить("Маршрут", "");
        ДанныеБилета.Вставить("Дата", "");
        ДанныеБилета.Вставить("Класс", "");
        ДанныеБилета.Вставить("Пассажир", "");
        ДанныеБилета.Вставить("ДопИнфо", "");
        ДанныеБилета.Вставить("ИсходнаяСтрока", СтрокаБилета); 
        
        ОстатокСтроки = СтрокаБилета;
        Результаты = Неопределено;
        
        // ШАГ 1: Извлекаем ТИП билета
        Результаты = РегВырТип.Найти(ОстатокСтроки);
        Если Результаты.Количество() > 0 Тогда
            ДанныеБилета.ТипБилета = СокрЛП(Результаты[0].Значение);
            ОстатокСтроки = СокрЛП(Сред(ОстатокСтроки, Результаты[0].Длина + 1));
        КонецЕсли;
        
        // ШАГ 2: Извлекаем ПЕРЕВОЗЧИКА и ИНН
        Результаты = РегВырПеревозчик.Найти(ОстатокСтроки);
        Если Результаты.Количество() > 0 Тогда
            Группы = Результаты[0].Группы;
            // В 1С Группы нумеруются с 0 для первой захваченной подстроки (...)
            Если Группы.Количество() > 0 И Группы[0] <> Неопределено Тогда
                ДанныеБилета.Перевозчик = СокрЛП(Группы[0].Значение);
            КонецЕсли;
            Если Группы.Количество() > 1 И Группы[1] <> Неопределено Тогда
                ДанныеБилета.ИНН = СокрЛП(Группы[1].Значение);
            КонецЕсли;
            
            ОстатокСтроки = СокрЛП(СтрЗаменить(ОстатокСтроки, Результаты[0].Значение, ""));
        КонецЕсли;
        
        // ШАГ 3: Извлекаем КЛАСС обслуживания
        Результаты = РегВырКласс.Найти(ОстатокСтроки);
        Если Результаты.Количество() > 0 Тогда
            Если Результаты[0].Группы.Количество() > 0 И Результаты[0].Группы[0] <> Неопределено Тогда
                ДанныеБилета.Класс = СокрЛП(Результаты[0].Группы[0].Значение);
            КонецЕсли;
            ОстатокСтроки = СокрЛП(СтрЗаменить(ОстатокСтроки, Результаты[0].Значение, ""));
        КонецЕсли;
        
        // ШАГ 4: Извлекаем ДАТУ, ПАССАЖИРА и ДОП. ИНФОРМАЦИЮ
        Результаты = РегВырДата.Найти(ОстатокСтроки);
        Если Результаты.Количество() > 0 Тогда
            ДанныеБилета.Дата = Результаты[0].Значение;
            
            ПозицияДаты = СтрНайти(ОстатокСтроки, ДанныеБилета.Дата);
            Хвост = СокрЛП(Сред(ОстатокСтроки, ПозицияДаты + СтрДлина(ДанныеБилета.Дата)));
            ОстатокСтроки = СокрЛП(Лев(ОстатокСтроки, ПозицияДаты - 1)); // Отрезаем от остатка
            
            // Разделяем Пассажира и ДопИнфо по первой запятой
            ПозЗапятой = СтрНайти(Хвост, ",");
            Если ПозЗапятой > 0 Тогда
                ДанныеБилета.Пассажир = СокрЛП(Лев(Хвост, ПозЗапятой - 1));
                ДанныеБилета.ДопИнфо  = СокрЛП(Сред(Хвост, ПозЗапятой + 1));
            Иначе
                ДанныеБилета.Пассажир = Хвост;
            КонецЕсли;
            
        Иначе
            // Бездатные билеты - ищем ФИО с конца строки
            Результаты = РегВырПассажир.Найти(ОстатокСтроки);
            Если Результаты.Количество() > 0 Тогда
                Если Результаты[0].Группы.Количество() > 0 И Результаты[0].Группы[0] <> Неопределено Тогда
                    ДанныеБилета.Пассажир = СокрЛП(Результаты[0].Группы[0].Значение);
                КонецЕсли;
                ОстатокСтроки = СокрЛП(Лев(ОстатокСтроки, СтрДлина(ОстатокСтроки) - Результаты[0].Длина));
            КонецЕсли;
        КонецЕсли;
        
        // ШАГ 5: Разделяем оставшееся на НОМЕР БИЛЕТА и МАРШРУТ
        ОстатокСтроки = СтрЗаменить(ОстатокСтроки, "Квитанция №", "");
        ОстатокСтроки = СтрЗаменить(ОстатокСтроки, "к билету №", "/ ");
        ОстатокСтроки = СтрЗаменить(ОстатокСтроки, "Исходный а/б №", "");
        ОстатокСтроки = СтрЗаменить(ОстатокСтроки, "Новый а/б №", "/ ");
        ОстатокСтроки = СтрЗаменить(ОстатокСтроки, "а/б №", "");
        ОстатокСтроки = СтрЗаменить(ОстатокСтроки, "№", "");
        ОстатокСтроки = СокрЛП(ОстатокСтроки);
        
        Результаты = РегВырНомерМаршрут.Найти(ОстатокСтроки);
        Если Результаты.Количество() > 0 Тогда
            Группы = Результаты[0].Группы;
            Если Группы.Количество() > 0 И Группы[0] <> Неопределено Тогда
                ДанныеБилета.НомерБилета = СокрЛП(Группы[0].Значение);
            КонецЕсли;
            Если Группы.Количество() > 1 И Группы[1] <> Неопределено Тогда
                ДанныеБилета.Маршрут = СокрЛП(Группы[1].Значение);
            КонецЕсли;
        Иначе
            ДанныеБилета.НомерБилета = ОстатокСтроки;
        КонецЕсли;
        
        Результат.Добавить(ДанныеБилета);
        
    КонецЦикла;
    
    Возврат Результат;

КонецФункции