Разработка и Конфигурация · 12 мин
Как найти строку в массиве в 1С: все способы с примерами
Как найти строку в массиве 1С: метод Найти(), поиск перебором в цикле, работа с массивами структур и таблицами значений. Примеры кода и типичные ошибки.
Поиск строки в массиве — одна из самых частых задач при разработке на встроенном языке 1С. Массивы используются повсеместно: для хранения списка выбранных товаров, отобранных документов, допустимых значений параметров, результатов разбора строк. В зависимости от того, что именно хранится в массиве (простые строки, ссылки, структуры) и что именно нужно найти (точное совпадение, вхождение подстроки, элемент по условию), применяются разные подходы.
Важно сразу различить две задачи, которые часто путают. Первая — найти элемент массива, равный заданной строке, и получить его индекс. Вторая — найти подстроку внутри строковой переменной (для этого существуют функции СтрНайти, Найти). В этой статье разбирается именно первая задача — поиск элемента в массиве, а также смежные сценарии: поиск по части строки, поиск в массиве структур и в таблице значений.
Метод Найти(): поиск точного совпадения
У объекта «Массив» есть встроенный метод Найти(Значение). Он выполняет последовательное сравнение каждого элемента с искомым значением и возвращает индекс первого найденного элемента. Индексация массивов в 1С начинается с нуля, поэтому первый элемент имеет индекс 0. Если совпадений нет, метод возвращает значение Неопределено.
МассивГородов = Новый Массив;
МассивГородов.Добавить("Москва");
МассивГородов.Добавить("Казань");
МассивГородов.Добавить("Самара");
Индекс = МассивГородов.Найти("Казань");
Если Индекс = Неопределено Тогда
Сообщить("Элемент не найден");
Иначе
Сообщить("Найден элемент с индексом: " + Индекс); // 1
КонецЕсли;
Сравнение строк выполняется с учётом регистра символов. Строка «казань» не будет найдена в массиве, где хранится «Казань». Это одна из самых частых причин «не работающего» поиска. Если регистр не гарантирован, приводите обе стороны к одному регистру через ВРег() или НРег() — но для этого уже потребуется перебор в цикле, потому что метод Найти() не умеет сравнивать с преобразованием.
Также учитывайте типы данных. Метод сравнивает значения с учётом типа: число 5 не равно строке «5». Если массив заполнялся из разных источников (например, часть элементов пришла из запроса, часть — из строкового разбора), поиск может не находить визуально совпадающие значения именно из-за различия типов.
Поиск перебором в цикле: когда Найти() недостаточно
Метод Найти() подходит только для точного равенства. Как только условие поиска усложняется — нужно вхождение подстроки, сравнение без учёта регистра, поиск по шаблону или по нескольким условиям — используется классический перебор массива в цикле.
ИскомаяПодстрока = "казан";
НайденныйЭлемент = Неопределено;
Для Каждого Элемент Из МассивГородов Цикл
Если СтрНайти(НРег(Элемент), НРег(ИскомаяПодстрока)) > 0 Тогда
НайденныйЭлемент = Элемент;
Прервать;
КонецЕсли;
КонецЦикла;
Если НайденныйЭлемент <> Неопределено Тогда
Сообщить("Найдено: " + НайденныйЭлемент);
КонецЕсли;
Здесь функция СтрНайти(Строка, Подстрока) возвращает позицию вхождения подстроки (начиная с 1) или 0, если вхождения нет. Обёртка в НРег() делает поиск нечувствительным к регистру. Оператор Прервать останавливает цикл после первого совпадения — это важно для производительности на больших массивах.
Если нужны все совпадения, а не первое, вместо Прервать собирайте результаты в новый массив:
Результат = Новый Массив;
Для Каждого Элемент Из МассивГородов Цикл
Если СтрНайти(НРег(Элемент), НРег(ИскомаяПодстрока)) > 0 Тогда
Результат.Добавить(Элемент);
КонецЕсли;
КонецЦикла;
- 1Определите, что хранится в массиве: простые строки, ссылки или структуры
- 2Для точного совпадения простых значений используйте Массив.Найти(Значение)
- 3Для поиска по подстроке, без учёта регистра или по условию — перебор в цикле со СтрНайти()
- 4Проверьте результат: индекс не равен Неопределено или найденный элемент заполнен
- 5Убедитесь, что типы искомого значения и элементов массива совпадают
Проверка вхождения без получения индекса
Часто индекс не нужен — требуется только ответить на вопрос «есть ли такое значение в массиве». Типовой сценарий: проверить, входит ли значение в список допустимых, например разрешён ли у пользователя доступ к складу из списка. Здесь тот же метод Найти() используется как условие:
ДопустимыеСклады = ПолучитьДопустимыеСклады(); // массив ссылок
Если ДопустимыеСклады.Найти(ТекущийСклад) = Неопределено Тогда
ВызватьИсключение "Склад недоступен текущему пользователю";
КонецЕсли;
Для ссылок на объекты базы (справочники, документы) сравнение работает корректно: ссылки сравниваются по уникальному идентификатору, а не по представлению. Поэтому искать ссылку по строковому наименованию через Найти() не получится — сначала получите ссылку (например, через Справочники.Номенклатура.НайтиПоНаименованию()), а уже её ищите в массиве.
Поиск в массиве структур и таблице значений
На практике в массивах часто хранятся не простые строки, а структуры — например, результат построчного разбора файла, где каждый элемент описывает товар с полями «Артикул», «Наименование», «Количество». Метод Найти() здесь бесполезен: структуры не сравниваются на равенство напрямую. Поиск выполняется перебором по нужному полю:
Для Каждого СтрокаТовара Из МассивТоваров Цикл
Если СтрокаТовара.Артикул = ИскомыйАртикул Тогда
// работа с найденной строкой
Прервать;
КонецЕсли;
КонецЦикла;
Если данных много и поиск выполняется неоднократно, разумнее на этапе формирования данных использовать не массив структур, а таблицу значений. У таблицы значений есть метод Найти(Значение, ИмяКолонки), который ищет по конкретной колонке, и метод НайтиСтроки(Отбор), возвращающий массив всех строк, удовлетворяющих отбору по нескольким полям:
Отбор = Новый Структура;
Отбор.Вставить("Артикул", ИскомыйАртикул);
Отбор.Вставить("Склад", ТекущийСклад);
НайденныеСтроки = ТаблицаТоваров.НайтиСтроки(Отбор);
Для Каждого Строка Из НайденныеСтроки Цикл
// обработка каждой найденной строки
КонецЦикла;
Сравнение способов поиска
Точное совпадение простых значений и ссылок. Быстро и коротко, но без поиска по части строки и без учёта регистра.
Гибкие условия: подстрока, регистр, вычисляемые проверки. Требует больше кода, при больших объёмах — внимание к Прервать.
Поиск по одному или нескольким полям структурированных данных. Требует хранить данные в таблице, а не в массиве.
Когда поиск выполняется многократно по ключу: ключ — строка, значение — произвольные данные. Выборка по ключу без перебора.
Оптимизация: соответствие вместо массива при частом поиске
И метод Найти(), и перебор в цикле — это последовательный проход по элементам. На массиве из нескольких десятков элементов разницы нет, но если массив содержит тысячи строк и поиск выполняется внутри другого цикла (например, при обработке каждой строки документа проверяется вхождение в список), суммарное время заметно растёт.
Решение — использовать объект «Соответствие», где искомая строка является ключом. Выборка из соответствия по ключу не требует перебора и выполняется практически мгновенно независимо от размера:
// Однократно строим соответствие из массива
СоответствиеПоиска = Новый Соответствие;
Для Каждого Элемент Из БольшойМассив Цикл
СоответствиеПоиска.Вставить(Элемент, Истина);
КонецЦикла;
// Далее многократно проверяем вхождение без перебора
Если СоответствиеПоиска.Получить(ИскомоеЗначение) <> Неопределено Тогда
// значение присутствует
КонецЕсли;
Тот же приём работает наоборот: если нужно получить по строке связанные данные (например, по артикулу — ссылку на номенклатуру), соответствие избавляет от повторных запросов к базе внутри цикла. Это одна из базовых техник ускорения обработок загрузки данных.
Частая причина «поиск не находит то, что точно есть» — непечатаемые символы: неразрывный пробел, перенос строки, символ табуляции в данных, пришедших из Excel или внешних файлов. Перед поиском очищайте строки функцией СокрЛП(), а при разборе файлов дополнительно заменяйте символы неразрывного пробела на обычные.
Типичные ошибки и как их избежать
Первая группа ошибок связана с неверной интерпретацией результата. Метод Найти() возвращает Неопределено при отсутствии элемента, и попытка использовать это значение как число (например, обратиться к Массив[Индекс] без проверки) приведёт к ошибке исполнения. Всегда проверяйте результат перед использованием.
Вторая группа — несовпадение типов и регистра. Строка из пользовательского ввода может содержать лишние пробелы по краям, другой регистр, а числовые значения могут храниться в массиве как числа, а искаться как строки. Унифицируйте данные перед сравнением: СокрЛП(), НРег(), приведение типов через Строка() или Число().
Третья группа — логические ошибки в циклах: отсутствие Прервать там, где нужен только первый результат, или наоборот — преждевременный Прервать, когда нужно собрать все совпадения. Перед написанием цикла чётко сформулируйте: нужен первый элемент, все элементы или только факт наличия.
Проверка результата и отладка
При отладке поиска полезно вывести содержимое массива и искомое значение рядом. В конфигураторе это делается через точку останова и табло: добавьте в табло выражение МассивГородов (его можно развернуть и посмотреть все элементы с типами) и выражение МассивГородов.Найти(ИскомоеЗначение). Так сразу видно, совпадают ли типы и есть ли значение в массиве в принципе.
Как проверить результат
Число от 0 до (Количество-1) — индекс найденного элемента
Неопределено — элемент не найден, обращаться к Массив[Индекс] нельзя
Тип искомого значения совпадает с типом элементов массива
Ищется строка, а в массиве числа или ссылки — сравнение всегда ложно
Строки совпадают посимвольно, без лишних пробелов
Ведущие/конечные пробелы, разный регистр, непечатаемые символы
Для прикладного кода, где поиск — часть бизнес-логики, добавляйте информативные сообщения при отрицательном результате: что искали и в каком наборе данных. Это существенно упрощает диагностику, когда пользователи сообщают, что «программа не находит» заведомо существующее значение.
Что важно запомнить
Для точного поиска простых значений и ссылок используйте Массив.Найти() и всегда проверяйте результат на Неопределено. Для поиска по подстроке, без учёта регистра или по полю структуры — перебор в цикле. Для структурированных данных удобнее таблица значений с НайтиСтроки(), а при многократном поиске в большом массиве — соответствие. Контролируйте типы, регистр и лишние пробелы в сравниваемых строках.
Частые вопросы
Как найти строку в массиве без учёта регистра?
Метод Найти() этого не умеет — используйте перебор в цикле со сравнением НРег(Элемент) = НРег(ИскомаяСтрока). Либо заранее приведите все элементы массива и искомую строку к одному регистру и тогда применяйте Найти().
Что вернёт Найти(), если в массиве несколько одинаковых строк?
Индекс первого по порядку совпадения. Метод прекращает поиск после первого найденного элемента. Если нужны индексы всех вхождений, используйте цикл с проверкой каждого элемента.
Можно ли искать в массиве по части строки?
Напрямую — нет. Переберите массив в цикле и для каждого элемента вызовите СтрНайти(Элемент, Подстрока): результат больше нуля означает, что подстрока найдена. Собирайте подходящие элементы в отдельный массив.
Как проверить, что массив вообще заполнен, перед поиском?
Используйте Массив.Количество(): если оно равно 0, искать нечего. Дополнительно проверяйте, что переменная инициализирована (не равна Неопределено), если массив мог быть не создан — иначе обращение к методу вызовет ошибку.
Чем поиск в массиве отличается от поиска в списке значений?
У списка значений метод НайтиПоЗначению() возвращает элемент списка (а не индекс), и элемент содержит помимо значения представление и пометку. Список значений удобен для интерактивного выбора, массив — для программной обработки.
Как найти строку в массиве на клиенте в управляемых формах?
Точно так же — метод Найти() и циклы доступны в клиентском контексте. Ограничение касается только обращения к базе данных: если для поиска нужны данные из запроса, выполняйте его на сервере и передавайте на клиент готовый массив.