При формировании печатных форм и отчетов разработчики часто сталкиваются со следующей проблемой: при сортировке текстового поля с адресом или номером квартиры значения выстраиваются в неудобном порядке — «1», «10», «100», «101», «2», «3» вместо ожидаемого арифметического порядка «1», «2», «3», ..., «100», «101».
Выясним причину такого поведения платформы 1С и подробно разберем несколько проверенных способов решения этой задачи.
Проанализируем механику работы платформы. По умолчанию текстовые поля (строковый тип данных) сравниваются посимвольно (лексикографически) слева направо. Символ «1» имеет меньший код, чем «2», поэтому любая строка, начинающаяся на «1» (например, «100»), расценивается системой как меньшая, чем строка «2».
Если вызвать метод Сортировать("Адрес Возр") для таблицы, содержащей строковые значения, платформой будет применен именно строковый алгоритм сравнения.
Рассмотрим самый распространений и гибкий вариант. Если номера квартир или домов хранятся отдельно или их можно извлечь, переведем их в числовой тип перед выводом на печать.
Разберем по шагам реализацию этого подхода:
Выгрузить().Число для хранения числового эквивалента номера квартиры.Число().Сортировать().Посмотрим на пример кода обработки данных перед печатью:
// Выгружаем данные из табличного поля во временную таблицу значений
ТЗ = ТабличноеПоле1.Выгрузить();
// Добавляем числовую колонку для правильной сортировки
ТЗ.Колонки.Добавить("КвартираЧисло", Новый ОписаниеТипов("Число"));
// Заполняем числовое поле
Для Каждого Стр Из ТЗ Цикл
// Преобразуем строковый номер квартиры в число
Стр.КвартираЧисло = Число(Стр.НомерКвартиры);
КонецЦикла;
// Сортируем по числовому значению
ТЗ.Сортировать("Улица Возр, ДомЧисло Возр, КвартираЧисло Возр");
// Выводим отсортированные данные в печатную форму
ТабДок = Новый ТабличныйДокумент();
Макет = Справочники.Абоненты.ПолучитьМакет("График");
Шапка = Макет.ПолучитьОбласть("Шапка");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
ТабДок.Вывести(Шапка);
Для Каждого Стр Из ТЗ Цикл
ОбластьСтрока.Параметры.Абонент = Стр.Абонент;
ОбластьСтрока.Параметры.Адрес = Стр.Адрес;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
ТабДок.Показать();
Бывают ситуации, когда в номере квартиры присутствуют буквенные индексы или помещения, например «3пом», «12Б» или «100А». Прямое преобразование всей строки через Число() в таком случае вызовет ошибку.
В этой ситуации сформируем служебный ключ сортировки, в котором числовая часть приводится к фиксированной длине с помощью лидирующих нулей функции Формат().
Рассмотрим пример формирования такого ключа:
// Извлекаем числовую часть (например, 3 из "3пом")
ЧисловаяЧасть = 3;
БуквенныйСуффикс = "пом";
// Приводим число к виду "000003"
КлючСортировки = Формат(ЧисловаяЧасть, "ЧЦ=6; ЧВН=; ЧГ=0") + БуквенныйСуффикс;
// Результат для 3пом: "000003пом"
// Результат для 100пом: "000100пом"
Сравнение строк «000003пом» и «000100пом» при обычной строковой сортировке даст верный результат: «3пом» выведется раньше, чем «100пом».
Если данные для печатной формы выбираются с помощью языка запросов 1С, а номер квартиры представляет собой чистую строку без букв, можно применить сортировку по длине строки.
Так как строка «3» имеет длину 1, а «10» — длину 2, упорядочивание сначала по длине строки, а затем по самому значению позволит получить корректный порядок:
ВЫБРАТЬ
Ссылка КАК Абонент,
Адрес КАК Адрес,
НомерКвартиры КАК НомерКвартиры
ИЗ
Справочник.Абоненты
УПОРЯДОЧИТЬ ПО
ДЛИНАСУБСТРОКИ(НомерКвартиры) ВОЗР,
НомерКвартиры ВОЗР
Обратите внимание: данный способ подходит только для чисто числовых строк фиксированного формата.
Для предотвращения подобных трудностей при дальнейшей разработке рекомендуется соблюдать следующие правила:
Число.