В практике программирования на платформе 1С:Предприятие 7.7 разработчики нередко сталкиваются с ситуациями, которые кажутся «мистическими». Программа либо игнорирует логические условия, либо внезапно зависает в бесконечном цикле. Рассмотрим типичный пример такой ситуации, проанализируем причины возникновения ошибок и найдем правильные способы их решения.
Проанализируем ситуацию, с которой столкнулся автор темы. Перед ним стояла задача: пропустить строки файла, если код операции не равен «11» и не равен «56». Автор написал следующее условие:
Если (КодОперации <> "11") ИЛИ (КодОперации <> "56") Тогда
Продолжить;
КонецЕсли;
На первый взгляд кажется, что код должен работать. Однако на практике это условие всегда будет истинным, какой бы код операции ни пришел на вход. Давайте выясним причину, рассмотрев разные варианты значения переменной КодОперации:
КодОперации равен "11". Проверяем первую часть: "11" <> "11" — это Ложь. Проверяем вторую часть: "11" <> "56" — это Истина. Поскольку используется оператор ИЛИ, общее выражение (Ложь ИЛИ Истина) дает Истину. Программа выполняет Продолжить.КодОперации равен "56". Проверяем первую часть: "56" <> "11" — это Истина. Вторую часть можно даже не проверять (хотя в 7.7 вычисляются обе части), результат уже будет Истина. Программа снова выполняет Продолжить.КодОперации равен "100". Обе части выражения истинны. Результат — Истина.Как мы видим, условие срабатывает всегда, потому что значение не может быть одновременно равно двум разным строкам. Чтобы условие работало корректно для исключения нескольких значений, необходимо использовать оператор И. Правильный вариант выглядит так:
Если (КодОперации <> "11") И (КодОперации <> "56") Тогда
Продолжить;
КонецЕсли;
Также можно воспользоваться законом Де Моргана и инвертировать условие равенства:
Если НЕ ((КодОперации = "11") ИЛИ (КодОперации = "56")) Тогда
Продолжить;
КонецЕсли;
В процессе обсуждения выяснилось, что при исправлении условия программа начала «виснуть». Рассмотрим подробнее фрагмент кода функции СформироватьМПАЙ, представленный автором:
Для А = 4 по ФайлЗагрузки.КоличествоСтрок() Цикл
// ... разбор строки ...
Иначе //здесь обработка отмены
Для А=1 По 50 Цикл
// ... какие-то действия ...
Прервать;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Проанализируем ситуацию: здесь используется переменная А в качестве счетчика внешнего цикла (перебор строк файла) и эта же самая переменная А используется во внутреннем цикле. Это критическая ошибка для 1С 7.7.
Когда выполнение заходит во внутренний цикл, значение переменной А сбрасывается в 1. После завершения внутреннего цикла (или выхода по Прервать), управление возвращается во внешний цикл. Внешний цикл видит, что его счетчик А теперь равен, например, 1 или 5, что значительно меньше, чем общее количество строк в файле. В результате цикл начинает обрабатывать одни и те же строки заново, что визуально воспринимается как «бесконечный цикл» или зависание.
Важное правило: никогда не используйте одну и ту же переменную для вложенных циклов. Всегда называйте итераторы по-разному, например, НомСтр и Инд.
В коде автора используется метод последовательного поиска разделителя (точки с запятой) и обрезания строки:
Поз = Найти(СтрокаИзФайла,";");
КодОперации = Лев(СтрокаИзФайла,Поз - 1);
СтрокаИзФайла = Сред(СтрокаИзФайла,Поз+1);
Хотя этот метод рабочий, он громоздок и неудобен в отладке. Рассмотрим более элегантные способы разбора строки в 1С 7.7:
Способ 1: Использование СтрЗаменить и СтрПолучитьСтроку
Мы можем заменить все точки с запятой на символы переноса строк. Тогда к каждому полю можно будет обратиться по индексу:
ПодготовленнаяСтрока = СтрЗаменить(СтрокаИзФайла, ";", РазделительСтрок);
КодОперации = СтрПолучитьСтроку(ПодготовленнаяСтрока, 4); // Например, код операции в 4-й колонке
ДатаОперации = СтрПолучитьСтроку(ПодготовленнаяСтрока, 2);
Способ 2: СписокЗначений и ИзСтрокиСРазделителями
Этот метод часто работает быстрее при большом количестве колонок:
Сп = СоздатьОбъект("СписокЗначений");
// Превращаем строку в формат, который понимает 1С (значения в кавычках через запятую)
ТекСтрока = """" + СтрЗаменить(СтрокаИзФайла, ";", """,""") + """";
Сп.ИзСтрокиСРазделителями(ТекСтрока);
КодОперации = Сп.ПолучитьЗначение(4);
Для успешного решения задачи загрузки данных из кассового ПО в 1С 7.7 мы выяснили следующее:
И с оператором «не равно» или НЕ с оператором ИЛИ внутри скобок.Для ... Цикл.Найти и Сред для одной строки; преобразование строки в многострочный текст или использование СписокЗначений делает код чище и понятнее.Соблюдение этих правил позволит вам писать надежный код и избегать «чудес», которые на самом деле являются следствием простой невнимательности к базовым принципам логики и работы платформы.