Как найти номер строки в многострочной строке 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработчика 1С часто возникает задача поиска вхождения определенного текста в большой многострочный массив данных. Ситуация усложняется, если искомая подстрока сама является многострочной (например, блок кода запроса или фрагмент лога). Простое использование функции Найти() возвращает индекс символа, но не номер строки. В этой статье мы разберем несколько эффективных способов решения этой задачи, проанализируем их производительность и рассмотрим важные нюансы работы с символами переноса строк.

Метод 1. Комбинация функций поиска позиции и подсчета строк

Рассмотрим наиболее изящный и короткий способ решения. Основная идея заключается в том, чтобы найти индекс первого символа искомой подстроки, «отрезать» часть исходного текста до этого индекса и посчитать количество строк в полученном фрагменте. Проанализируем, как это реализовать программно:


// Исходные данные
Стр1 = "Строка11
|Строка12
|Строка2
|Строка3
|Строка4";

Стр2 = "Строка2
|Строка3";

// Алгоритм поиска
ПозицияСимвола = Найти(Стр1, Стр2);

Если ПозицияСимвола > 0 Тогда
    // Отсекаем текст ПЕРЕД найденным вхождением
    ФрагментДоВхождения = Лев(Стр1, ПозицияСимвола - 1);
    // Считаем количество строк в этом фрагменте
    НомерСтроки = СтрКоличествоСтрок(ФрагментДоВхождения);
    Сообщить("Искомый текст начинается со строки номер: " + НомерСтроки);
КонецЕсли;

Почему это работает? В системе 1С функция СтрКоличествоСтрок() возвращает минимум 1, даже для пустой строки. Если искомая подстрока Стр2 находится в самом начале Стр1, функция Лев() вернет пустую строку, а СтрКоличествоСтрок("") вернет 1, что соответствует действительности.

Метод 2. Использование функции СтрНайти (для платформы 8.3.10 и выше)

Разберем более современный подход. Платформа 1С постоянно развивается, и начиная с версии 8.3.10, разработчикам доступна функция СтрНайти(). Она работает быстрее и обладает расширенными параметрами. Посмотрим на пример кода с её использованием:


// Используем СтрНайти для определения позиции
Позиция = СтрНайти(Стр1, Стр2, НаправлениеПоиска.СНачала);

Если Позиция > 0 Тогда
    // Номер строки вычисляется аналогично методу выше
    НомерСтроки = СтрКоличествоСтрок(Лев(Стр1, Позиция - 1));
КонецЕсли;

Преимущество СтрНайти в том, что мы можем указать НачальнаяПозиция. Это критически важно, если нам нужно найти не первое, а второе или все последующие вхождения подстроки в текст. Мы можем организовать цикл, передавая позицию предыдущего найденного фрагмента + 1 в качестве параметра начала поиска.

Метод 3. Работа с объектом ТекстовыйДокумент

Выясним, как решить задачу, если текст уже загружен в объект ТекстовыйДокумент или если нам требуется более сложная логика поиска (например, с учетом регистра или поиска только целых слов). У этого объекта есть встроенный метод НайтиТекст().

Рассмотрим по шагам работу с этим методом:

  1. Создаем объект ТекстовыйДокумент и загружаем в него текст.
  2. Вызываем метод НайтиТекст(), передавая искомую строку.
  3. Метод возвращает область поиска или Неопределено.

ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.УстановитьТекст(Стр1);

// Параметры: ЧтоИщем, Направление, ПоискЦелыхСлов, УчитыватьРегистр
ОбластьПоиска = ТекстДок.НайтиТекст(Стр2);

Если ОбластьПоиска <> Неопределено Тогда
    Сообщить("Найдено в строке: " + ОбластьПоиска.Верх);
КонецЕсли;

Важно помнить, что ТекстовыйДокумент работает медленнее, чем прямые строковые функции, особенно на очень больших объемах данных. Однако он возвращает координаты сразу (строка начала, колонка начала, строка конца, колонка конца), что избавляет нас от дополнительных вычислений.

Важный нюанс: Проблема символов переноса строки (CRLF vs LF)

Проанализируем ситуацию, когда поиск может не сработать. В 1С стандартный разделитель строк — Символы.ПС (код 10). Но в файлах Windows часто используется связка Символы.ВК + Символы.ПС (код 13 и код 10). Если в исходном тексте Стр1 используются одни символы, а в Стр2 — другие, функция Найти() вернет 0.

Для предотвращения ошибок рекомендуем всегда выполнять нормализацию текста перед поиском:


// Заменяем все возвраты каретки на пустую строку, оставляя только перенос строки
Стр1_Норм = СтрЗаменить(Стр1, Символы.ВК, "");
Стр2_Норм = СтрЗаменить(Стр2, Символы.ВК, "");

Позиция = Найти(Стр1_Норм, Стр2_Норм);

Метод 4. Построчный перебор (для очень больших текстов)

Если ваша строка занимает сотни мегабайт, метод с использованием Лев() может вызвать переполнение памяти, так как 1С придется создать копию огромного фрагмента текста. В таких случаях рассмотрим алгоритм построчного чтения:


// Допустим, мы ищем первую строку из многострочного шаблона Стр2
МассивСтр2 = СтрРазделить(Стр2, Символы.ПС, Ложь);
ПерваяСтрокаПоиска = МассивСтр2[0];

ТекстЧтение = Новый ЧтениеТекста;
// ... инициализация чтения из файла или потока ...

ТекущийНомерСтроки = 0;
Пока Истина Цикл
    ТекущийНомерСтроки = ТекущийНомерСтроки + 1;
    Стр = ТекстЧтение.ПрочитатьСтроку();
    Если Стр = Неопределено Тогда Прервать; КонецЕсли;

    Если Найти(Стр, ПерваяСтрокаПоиска) > 0 Тогда
        // Здесь можно реализовать проверку последующих строк для подтверждения полного совпадения Стр2
        Сообщить("Возможное вхождение в строке: " + ТекущийНомерСтроки);
    КонецЕсли;
КонецЦикла;

Подведем итоги:

Выбрав правильный инструмент, вы обеспечите высокую скорость работы программы и надежность кода при обработке многострочных данных.

← На главную