Книга знаний

1С:Предприятие / v8 / Приемы программирования / Встроенный язык

v8: Простой анализ текстовых строк по маркерам в тексте

Иногда нужно разбить строку по шаблону. Можно заняться регулярными выражениями, но иногда задачу можно решить проще.Автор статьи: Гений 1С | Редакторы: Fragster
Последняя редакция №2 от 13.02.08 | История
URL: http://kb.mista.ru/article.php?id=637

Ключевые слова: строки,маркеры,парсинг,регулярные выражения


У меня была такая строка в Excel, нужно было выделить из нее две суммы - сумму за электроэнергию и сумму за мощность.

42 418 838 руб.,
15 коп. за
электроэнергию
за период
с 01.01
по 06.01
12 148 608 руб.,
06 коп. за
мощность

Программист, который работал до меня, тупо ориентировался на позицию строки "Электроэнергию", в общем код был такой:

Функция РаспознатьСуммыПлатежей(ЗнЯчейки)
    
    СтрЭ = Прав(СтрЭ,СтрДлина(СтрЭ) - руб-4);
    коп  = Найти(СтрЭ,"коп");
    КопЭ = ___обВЧислоИлиНоль(СтрЗаменить(СокрЛП(Лев(СтрЭ,коп-1))," ",""));
    // Мощность
    
    
    Э = Найти(ЗнЯчейки,"электроэнергию");
    СтрЭ = Лев(ЗнЯчейки,Э - 1);
    СтрМ = Прав(ЗнЯчейки,СтрДлина(ЗнЯчейки) - Э - 14);
    СтрП = Найти(СтрМ,"за период");
    Если СтрП = 1 Тогда
        СтрМ = Прав(СтрМ,СтрДлина(СтрМ) - 36);
    КонецЕсли;
    
    // Электроэнергия
    руб = Найти(СтрЭ,"руб");
    РубЭ = ___обВЧислоИлиНоль(СтрЗаменить(СокрЛП(Лев(СтрЭ,руб-1))," ",""));
    СтрЭ = Прав(СтрЭ,СтрДлина(СтрЭ) - руб-4);
    коп  = Найти(СтрЭ,"коп");
    КопЭ = ___обВЧислоИлиНоль(СтрЗаменить(СокрЛП(Лев(СтрЭ,коп-1))," ",""));
    // Мощность
    руб = Найти(СтрМ,"руб");
    РубМ = ___обВЧислоИлиНоль(СтрЗаменить(СокрЛП(Лев(СтрМ,руб-1))," ",""));
    СтрМ = Прав(СтрМ,СтрДлина(СтрМ) - руб-4);
    коп  = Найти(СтрМ,"коп");
    КопМ = ___обВЧислоИлиНоль(СтрЗаменить(СокрЛП(Лев(СтрМ,коп-1))," ",""));
    
    Возврат Новый Структура("Ошибка, РубМ, КопМ, РубЭ, КопЭ", ложь, РубМ, КопМ, РубЭ, КопЭ);
КонецФункции


Но потребовалось более интеллектуальное распознавание, т.к. иногда год записывали через два знака, иногда через четыре, в результате такое позиционирование не годилось.

Я использовал распознавание, ориентированное на маркеры:

Функция РаспознатьСуммыПлатежей(ЗнЯчейки)
    М=Новый Массив();
    М.Добавить("руб");
    М.Добавить("коп");
    М.Добавить("по");
    М.Добавить(Символы.ПС);
    М.Добавить("руб");
    М.Добавить("коп");
    Р=___обСоответствиеСтрокиМаркерам(ЗнЯчейки, М);
    Если Р=Неопределено Тогда
        Возврат Новый Структура("Ошибка, РубМ, КопМ, РубЭ, КопЭ", истина, 0, 0, 0, 0);
    КонецЕсли;
    
    РубЭ = Число(___обИзвлечьЦифрыИзСтроки(Р[0]));
    КопЭ = Число(___обИзвлечьЦифрыИзСтроки(Р[1]));
    
    РубМ = Число(___обИзвлечьЦифрыИзСтроки(Р[4]));
    КопМ = Число(___обИзвлечьЦифрыИзСтроки(Р[5]));
    
    Возврат Новый Структура("Ошибка, РубМ, КопМ, РубЭ, КопЭ", ложь, РубМ, КопМ, РубЭ, КопЭ);
КонецФункции



//fixin 20080212
//Извлекает цифры из строки, только цифры
//Возвращает строку с цифрами
Функция ___обИзвлечьЦифрыИзСтроки(С)
    Р="";
    Для Инд=1 По СтрДлина(С) Цикл
        Симв=Сред(С, Инд, 1);
        Если Найти("0123456789", Симв)<>0 Тогда
            Р=Р+Симв;
        КонецЕсли;
    КонецЦикла;
    Возврат Р;
КонецФункции

//fixin 20080212
//Ищет в строке С маркеры М и выдает массив разбиений
//Если разложить не получилось, то выдает Неопределено
//Пример:
// "100 руб. 50 коп.", {"руб","коп"} => {"100 " ". 50 ", "."}
// "100 руб", {"руб","коп"} => Неопределено
Функция ___обСоответствиеСтрокиМаркерам(_С, М, УчитыватьРегистр=ложь)
    Перем С, ДлинаСтроки, Р, ТекСтрока, Поз, ДлинаМаркера, ТекМаркер, ИскМаркер;
    Если УчитыватьРегистр Тогда
        С=_С;
    Иначе
        С=ВРег(_С);
    КонецЕсли;
    
    ДлинаСтроки=СтрДлина(С);
    
    //Массив для возврата
    Р=Новый Массив();
    
    ТекСтрока=""; //Текущая строка для анализа
    
    //Позиция анализа
    Поз=1;
    ТекСтрока="";
    //Ищем очередной маркер
    НайденоМаркеров=0;
    Для Каждого ЭлМаркер Из М Цикл
        ДлинаМаркера=СтрДлина(ЭлМаркер);
        Если УчитыватьРегистр Тогда
            ТекМаркер=ЭлМаркер;
        Иначе
            ТекМаркер=ВРег(ЭлМаркер);
        КонецЕсли;
        
        
        Пока (Поз<=ДлинаСтроки) Цикл
            //Смотрим, получаем ли мы текущий маркер в текущей позиции
            ИскМаркер=Сред(С, Поз, ДлинаМаркера);
            Если ИскМаркер=ТекМаркер Тогда
                Р.Добавить(ТекСтрока);
                ТекСтрока="";
                НайденоМаркеров=НайденоМаркеров+1;
                Поз=Поз+ДлинаМаркера; //Сдвигаем позицию
                Прервать;
            КонецЕсли;
            ТекСтрока=ТекСтрока+Сред(С, Поз, 1);
            Поз=Поз+1;
        КонецЦикла;
    КонецЦикла;
    Р.Добавить(Сред(С, Поз)); //Хвостик добавляем
    
    Если НайденоМаркеров=М.Количество() Тогда
        Возврат Р;
    Иначе
        Возврат Неопределено;
    КонецЕсли;
    
КонецФункции


Такое распознавание проще и надежнее. Проще, чем регулярные выражения. рекомендую.

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика