Предыстория
Как-то при переносе данных в одну животноводческую базу, я столкнулся со странным поведением выполнения довольно простого кода. У меня было множество животных с уникальными шифрами, описывающими их породу. Те, кто помнят школьные уроки по генетики, знают, что доминантные гены принято изображать большими буквами, а рецессивные — маленькими. Для остальных небольшая иллюстрация для понимания:
размер имеет значение
Казалось бы, что загрузку написал правильно, но результат в базе не соответствовал данным источника — данные по некоторым животным были перепутаны, а по части вообще ничего не загрузилось. Пристальное изучение несоответствий показало, что путаница наблюдались в тех случаях, когда шифры животных различались не составом, а только регистром.
Поиск по данным в базе
Давайте попробуем воссоздать пример с картинки выше и создадим справочник "Виды цветов" с тремя элементами: АА -> красный, Аа -> розовый и аа -> белый. Проблему можно увидеть сразу, если попытаться наш код внести в стандартное поле "Код":
скрин
Заметим, что таким образом мы можем задать элементу справочника код А00001 и при автонумерации получим А00002, А00003 и так далее. Так же мы можем задать код а00001 и получить а00002, а00003… Но если мы при наличии А00001 по какой-то причине захотим установить номер а00001, то получить "облом".
Аналогичное поведение при тестировании кодов/номеров я обнаружел у документов, задач, бизнес-процессов, планов видов характеристик, планов счетов и планов обмена. Но у планов видов расчетов, однако, разрешается создать одновременно элементы с номерами "А00001" и "а00001", что очень странно — тут можно было бы сослаться на то, что у плана видов расчетов в настройках отсутствует свойство включения/отключения контроля уникальности номера, но этого свойства так же нет и у плана обменов. В документации о такой выборочно действующей особенности поведения ничего не написано. Если я просто не увидел, то напишите в комментариях.
Кстати, поскольку удалось создать несколько видов расчета с идентичными кодами, то это прекрасный повод проверить результат функции НайтиПоКоду(). Только предварительно я воспользуюсь отсутствием у плана видов расчетов контроля уникальности номеров и добавлю еще один элемент с большой "А" — интересно какой из этих двух элементов будет выбран:
скрин
Да, уж. Согласитесь, результат оказался неожиданным и он подтверждает ранее замеченное наблюдение, что для платформы 1С регистр символов как минимум в кодах/номерах значения не умеет. Выходит, создавая код на нашей платформе, программист получает по факту выполнения: 1040 = КодСимвола("А") = КодСимвола("а") = 1072 , и лишь конечный пользователь системы видит на экране реальные символы.
Но продолжим нашу проверку. Обычно на практике для всяких внешних кодов используют реквизиты — в моем случае было так же. Создадим такой для справочника "Виды цветов" и попробуем воспользоваться другим стандартным поисковым методом — НайтиПоРеквизиту():
скрин
Как раз с этим я и столкнулся при переносе — в поиске по реквизиту регистр символов игнорируется.
Хотя, как оказывается, не обязательно быть программистом, что бы испытать дискомфорт при точном поиске — аналогичное поведение наблюдается и при использовании отборов СКД в динамическом списке (видимо одна и та же поисковая функция из внутренней библиотеки):
скрин
Для полноты картины, давайте протестируем последний оставшийся метод — ПоискПоНаименованию() и получим тот же результат (даже требование "точного соответствия" не помогло):
скрин
Итак, поисковые методы менеджеров объектов отказываются правильно искать чувствительные к регистру символов данные. А можно ли самостоятельно создать подобные методы с помощью механизма запросов? Давайте попробуем:
скрины
Как видите, ни использования оператора "=" в тексте запроса, ни оператор "Подобно" не помогли — каждый раз выбираются все похожие элементы, игнорируя регистры символов.
Т.е. для текста запроса, который транслируется в SQL и выполняется во внешних СУБД, снова верно выражение: 1040 = КодСимвола("А") = КодСимвола("а") = 1072. Я уже приготовился, что все во что я верил ложно и в мире 1С будет справделиво ("А" = "а") = Истина, но к счастью хотя бы примитивное сравнение строк работает и нужную нам функцию все же можно создать:
скрин
Поиск по коллекциям
С данными базы как мы уже убедились — грустно. А как дело обстоит с коллекциями?
Массив — обнаружена чувствительность к регистру символов в обычном и фиксированном вариантах для метода Найти().
код и результаты
Таблица значений — методы Найти() и НайтиСтроки() чувствительны к регистру.
код и результаты
Список значений — метод НайтиПоЗначению() чувствителен к регистру символов.
код и результаты
Структура — поисковые методы отсутствуют, а ключи регистр игнорируют.
код и результаты
Соответствие — поисковые методы отсутствуют, но зато поддерживаются ключи в разных регистрах.
код и результаты
Заключение
Я понимаю, что разработчики платформы хотели упростить работу бабушек из бухгалтерии, что бы те не тянулись к Shift (или даже CapsLock) и при наборе "вова" в поле ввода у них сразу выбрался "Вова". Только я отказываюсь понимать — почему из-за этого "облегчения труда" должны страдать разработчики конфигураций. Зачем и нам навязали отсутствие у строк регистра? Ведь именно нам-то как раз "вова" и "Вова" различать нужно (или пути в линуксах, или буквы "м" и "М" в форматных строках, или…). Да и самим пользователям иногда в списке нужно найти единственного человека с фамилией "Кар", а не увидеть сотню макарычей.
Выход, как мы видим, существует. Тут можно написать поисковую функцию с перепроверкой результата. Еще можно вместо поиска перед основным алгоритмом создать соответствие, где по строковым ключам загнать значение соответствующих ссылок. Но хотелось бы применять подобные костыли реже.
P.S. Если кто-нибудь до сих пор этого не знал, то открою тайну — пароль на вход в 1С тоже нечувствителен к регистру! 😉
Разработчики 1С не виноваты, скорей разработчики MS SQL Serverа!
Господи, пароль не чувствителен к регистру! Сколько лет я был в неведении! Как теперь с этим жить? Почему? Зачем? о_О
(1) Как не виновны, если они сами коллейшн регистронезависимый для базы ставят?
А скуль умеет и так, и так…
1. Всё это поведение описано в документации и вполне логично понимается где будет регистрозависимый «поиск» в зависимости от используемого объекта.
2. Про пароли ещё интересней. Хранится два хэша: от правильного пароля и от приведённого в верхний (или нижний уже точно не вспомню) регистр. Но для чего это сделано всё равно загадка) Наверно чтобы подбирать было проще. А ещё из-за кривой реализации сохранения рядом с хэшами можно было наблюдать пароль вообще в открытом виде!!!!
(1) такое же поведение в файловой базе.
Кстати, не совсем так, из справки:
Конфигуратор 1С:Предприятие 8. Параметры информационной базы
…
Проверка сложности паролей пользователей. Если данный параметр установлен, пароли пользователей должны удовлетворять следующим требованиям:
длина пароля не должна быть менее значения, указанного в параметре Минимальная длина паролей пользователей;
пароль должен состоять из символов, относящихся как минимум к трем из перечисленных групп:
заглавные буквы;
строчные буквы;
цифры;
специальные символы ;
пароль не должен совпадать с именем пользователя;
пароль не должен являться последовательностью символов.
Если параметр не установлен, то проверка пароля в процессе аутентификации регистронезависима.
Использование ограничений на пароли пользователей информационной базы не влияет на существующие пароли. Ограничения будут применены только при изменении существующего пароля или при добавлении нового пользователя информационной базы.
Показать
Зачем такие сложности? Если очень надо храните двоичные данные строки в строковом реквизите. Это элементарный код. Функции ПолучитьДвоичныеДанныеИзСтроки, ПолучитьДвоичныеДанныеИзHexСтроки и ПолучитьСтрокуИзДвоичныхДанных спасут ваш мир)))
(6) вот только про эту настройку знают единицы. За более чем десятилетнюю практику видел использование такой настройки только один раз. На крупных компаниях применяют доменную авторизацию, а в мелких предпочитают использовать стандартные пароли: «1», «123»… или вообще входят без паролей (если в базе только директор и главбух).
(7) тоже была такая идея, но не стал использоваться — хотел оставить для пользователя нормальную видимость.
(9) может я конечно чего то не учитываю, но не совсем понимаю проблемы сделать для пользователя нормальную видимость.
(9) На форме
Показать
И если требуется в модуле менеджера, что бы выводить поле в представление или что бы подбор с регистром работал
Показать
(9) Единственный минус, если поле слишком длинное, то индексировать не получиться. Максимальная срока 630 символов при котором поле 1с индексируется, а это получается 157 символов для поля с регистром. Так что реквизит формы желательно будет ограничить, если будет требоваться получать список выбора по полю.
(2) На сколько помню в конфигураторе есть флаг, который включает контроль.
(11) для поля наименования покатит (если представление по наименованию) и в динамических списках выводить не Наименование, а Ссылка. А что с реквизитами? На формах списков/выборов писать варианты ПриПолученииДанных (для ОФ и УФ по разному) и делать функции общих модулей для расчета представления полей в отчетах на компоновке? Как-то уж слишком большая цена за возможность регистрозависимого поиска — дешевле в модуле менеджера справочника дописать свою поисковую функцию.
(14)
Зачем вообще такой реквизит нужен, если по нему не делается ввод по строке? Или не делается поиск в формах списка/выбора? Искать по наименованию в модулях? Я промолчу, что я об этом думаю.
Зачем? Эти функции можно использовать в вычисляемых полях.
Считывание лишних данных всегда дороже. К тому же отсутствие возможности создания поиска в формах списка/выбора.
(4)
Это чтобы, в зависимости от настройки в базе, сравнивать либо с чувствительностью к регистру, либо без.
Если без чувствительности, то введённый пользователем пароль вводится в верхний регистр и его хэш сравнивается с хэшом в базе.
А как сделать так, чтобы отборы СКД и динамических списков у пользователей «чувствительно» отрабатывали?
(17) к счастью, класс задач с чувствительностью к регистру не очень широкий.
В тех случаях, когда нужно на формах делать регистрочувствительный фильтр — нужно делать этот фильтр самому. В зависимости от данных есть разные пути. Для небольшой выборки, когда отклонений много — запросом и повторным сравнением отобрать нужные ссылки и наложить на динамический список отбор по Ссылка ВСписке. Если выборка большая и мало отклонений — оставить Реквизит Равно/Подобно/Содержит, а с помощью функции отобрать именно отклонения для второго условия отбора — Ссылка НеВСписке.