1С и чувствительность к регистру [поход на грабли]

04.02.19

Разработка - Механизмы платформы 1С

Всем известно, что исполняемый код для платформы 1С не чувствителен к регистру символов. Некоторый особенные люди считают себя одаренными и пользуются этой возможностью, чтобы писать в своем уникальном стиле либо все маленькими буквами, либо наоборот большими. Оставим эти глупости на совести таких разработчиков, ведь нам же главное не "красота" в режиме конфигуратора, а чтобы обрабатываемые нами данные оставались аутентичными. Что бы "А" (код 1040) и "а" (код 1072) или "T" (код 84) и "t" (код 116) всегда оставались сами собой и превращались друг в друга только под нашим чутким контролем с помощью ВРег() и НРег(). К сожалению, бывает не всегда так, что может приводить к неожиданным ошибкам.

Предыстория

Как-то при переносе данных в одну животноводческую базу, я столкнулся со странным поведением выполнения довольно простого кода. У меня было множество животных с уникальными шифрами, описывающими их породу. Те, кто помнят школьные уроки по генетики, знают, что доминантные гены принято изображать большими буквами, а рецессивные - маленькими. Для остальных небольшая иллюстрация для понимания:

 
 размер имеет значение

Казалось бы, что загрузку написал правильно, но результат в базе не соответствовал данным источника - данные по некоторым животным были перепутаны, а по части вообще ничего не загрузилось. Пристальное изучение несоответствий показало, что путаница наблюдались в тех случаях, когда шифры животных различались не составом, а только регистром.

 

Поиск по данным в базе

Давайте попробуем воссоздать пример с картинки выше и создадим справочник "Виды цветов" с тремя элементами: АА -> красный, Аа -> розовый и аа -> белый. Проблему можно увидеть сразу, если попытаться наш код внести в стандартное поле "Код":

 
 скрин

Заметим, что таким образом мы можем задать элементу справочника код А00001 и при автонумерации получим А00002, А00003 и так далее. Так же мы можем задать код а00001 и получить а00002, а00003... Но если мы при наличии А00001 по какой-то причине захотим установить номер а00001, то получить "облом".

Аналогичное поведение при тестировании кодов/номеров я обнаружел у документов, задач, бизнес-процессов, планов видов характеристик, планов счетов и планов обмена. Но у планов видов расчетов, однако, разрешается создать одновременно элементы с номерами "А00001" и "а00001", что очень странно - тут можно было бы сослаться на то, что у плана видов расчетов в настройках отсутствует свойство включения/отключения контроля уникальности номера, но этого свойства так же нет и у плана обменов. В документации о такой выборочно действующей особенности поведения ничего не написано. Если я просто не увидел, то напишите в комментариях.

Кстати, поскольку удалось создать несколько видов расчета с идентичными кодами, то это прекрасный повод проверить результат функции НайтиПоКоду(). Только предварительно я воспользуюсь отсутствием у плана видов расчетов контроля уникальности номеров и добавлю еще один элемент с большой "А" - интересно какой из этих двух элементов будет выбран:

 
 скрин

Да, уж. Согласитесь, результат оказался неожиданным и он подтверждает ранее замеченное наблюдение, что для платформы 1С регистр символов как минимум в кодах/номерах значения не умеет. Выходит, создавая код на нашей платформе, программист получает по факту выполнения: 1040 = КодСимвола("А") = КодСимвола("а") = 1072 , и лишь конечный пользователь системы видит на экране реальные символы.

Но продолжим нашу проверку. Обычно на практике для всяких внешних кодов используют реквизиты - в моем случае было так же. Создадим такой для справочника "Виды цветов" и попробуем воспользоваться другим стандартным поисковым методом - НайтиПоРеквизиту():

 
 скрин

Как раз с этим я и столкнулся при переносе - в поиске по реквизиту регистр символов игнорируется.

Хотя, как оказывается, не обязательно быть программистом, что бы испытать дискомфорт при точном поиске - аналогичное поведение наблюдается и при использовании отборов СКД в динамическом списке (видимо одна и та же поисковая функция из внутренней библиотеки):

 
 скрин

Для полноты картины, давайте протестируем последний оставшийся метод - ПоискПоНаименованию() и получим тот же результат (даже требование "точного соответствия" не помогло):

 
 скрин

Итак, поисковые методы менеджеров объектов отказываются правильно искать чувствительные к регистру символов данные. А можно ли самостоятельно создать подобные методы с помощью механизма запросов? Давайте попробуем:

 
 скрины

Как видите, ни использования оператора "=" в тексте запроса, ни оператор "Подобно" не помогли - каждый раз выбираются все похожие элементы, игнорируя регистры символов.

Т.е. для текста запроса, который транслируется в SQL и выполняется во внешних СУБД, снова верно выражение: 1040 = КодСимвола("А") = КодСимвола("а") = 1072. Я уже приготовился, что все во что я верил ложно и в мире 1С будет справделиво ("А" = "а") = Истина, но к счастью хотя бы примитивное сравнение строк работает и нужную нам функцию все же можно создать:

 
 скрин

 

Поиск по коллекциям

С данными базы как мы уже убедились - грустно. А как дело обстоит с коллекциями? 

Массив - обнаружена чувствительность к регистру символов в обычном и фиксированном вариантах для метода Найти().

 
 код и результаты

Таблица значений - методы Найти() и НайтиСтроки() чувствительны к регистру.

 
 код и результаты

Список значений - метод НайтиПоЗначению() чувствителен к регистру символов.

 
 код и результаты

Структура - поисковые методы отсутствуют, а ключи регистр игнорируют.

 
код и результаты 

Соответствие - поисковые методы отсутствуют, но зато поддерживаются ключи в разных регистрах.

 
код и результаты 

 

Заключение

Я понимаю, что разработчики платформы хотели упростить работу бабушек из бухгалтерии, что бы те не тянулись к Shift (или даже CapsLock) и при наборе "вова" в поле ввода у них сразу выбрался "Вова". Только я отказываюсь понимать - почему из-за этого "облегчения труда" должны страдать разработчики конфигураций. Зачем и нам навязали отсутствие у строк регистра? Ведь именно нам-то как раз "вова" и "Вова" различать нужно (или пути в линуксах, или буквы "м" и "М" в форматных строках, или...). Да и самим пользователям иногда в списке нужно найти единственного человека с фамилией "Кар", а не увидеть сотню макарычей.

Выход, как мы видим, существует. Тут можно написать поисковую функцию с перепроверкой результата. Еще можно вместо поиска перед основным алгоритмом создать соответствие, где по строковым ключам загнать значение соответствующих ссылок. Но хотелось бы применять подобные костыли реже.

P.S. Если кто-нибудь до сих пор этого не знал, то открою тайну - пароль на вход в 1С тоже нечувствителен к регистру! ;)

ошибки программирования

См. также

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    4485    dsdred    53    

71

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    5286    YA_418728146    25    

63

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6401    dsdred    36    

111

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    18466    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12086    human_new    27    

74

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    8805    YA_418728146    6    

141

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6274    sebekerga    54    

94

Все скопируем и вставим! (Буфер обмена в 1С 8.3.24)

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Рассмотрим новую возможность 8.3.24 и как её можно эффективно использовать

27.06.2023    15976    SeiOkami    31    

103
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. PowerBoy 3350 04.02.19 11:10 Сейчас в теме
Зачем и нам навязали отсутствие у строк регистра?

Разработчики 1С не виноваты, скорей разработчики MS SQL Serverа!
3. DenisCh 04.02.19 11:44 Сейчас в теме
(1) Как не виновны, если они сами коллейшн регистронезависимый для базы ставят?
А скуль умеет и так, и так...
5. Dementor 1015 04.02.19 17:14 Сейчас в теме
(1) такое же поведение в файловой базе.
2. fxmike 70 04.02.19 11:16 Сейчас в теме
Господи, пароль не чувствителен к регистру! Сколько лет я был в неведении! Как теперь с этим жить? Почему? Зачем? о_О
dammit666; Поручик; AliceLight; Kinestetik; TreeDogNight; awk; serg_gres; KroVladS; Orlando Skibraves; s_vidyakin; Dementor; acanta; +12 Ответить
13. Дмитрий74Чел 234 05.02.19 14:03 Сейчас в теме
(2) На сколько помню в конфигураторе есть флаг, который включает контроль.
Прикрепленные файлы:
michmich; Бэнни; +2 Ответить
19. пользователь 21.02.19 09:06
Сообщение было скрыто модератором.
...
4. A_Max 19 04.02.19 12:38 Сейчас в теме
1. Всё это поведение описано в документации и вполне логично понимается где будет регистрозависимый "поиск" в зависимости от используемого объекта.
2. Про пароли ещё интересней. Хранится два хэша: от правильного пароля и от приведённого в верхний (или нижний уже точно не вспомню) регистр. Но для чего это сделано всё равно загадка) Наверно чтобы подбирать было проще. А ещё из-за кривой реализации сохранения рядом с хэшами можно было наблюдать пароль вообще в открытом виде!!!!
Kinestetik; Dementor; acanta; Glebis; +4 Ответить
16. SeiOkami 3423 08.02.19 09:09 Сейчас в теме
(4)
Хранится два хэша: от правильного пароля и от приведённого в верхний (или нижний уже точно не вспомню) регистр. Но для чего это сделано всё равно загадка) Наверно чтобы подбирать было проще.


Это чтобы, в зависимости от настройки в базе, сравнивать либо с чувствительностью к регистру, либо без.
Если без чувствительности, то введённый пользователем пароль вводится в верхний регистр и его хэш сравнивается с хэшом в базе.
6. zqzq 23 05.02.19 09:24 Сейчас в теме
P.S. Если кто-нибудь до сих пор этого не знал, то открою тайну - пароль на вход в 1С тоже нечувствителен к регистру! ;)

Кстати, не совсем так, из справки:

Конфигуратор 1С:Предприятие 8. Параметры информационной базы
...
Проверка сложности паролей пользователей. Если данный параметр установлен, пароли пользователей должны удовлетворять следующим требованиям:
длина пароля не должна быть менее значения, указанного в параметре Минимальная длина паролей пользователей;
пароль должен состоять из символов, относящихся как минимум к трем из перечисленных групп:
заглавные буквы;
строчные буквы;
цифры;
специальные символы ;
пароль не должен совпадать с именем пользователя;
пароль не должен являться последовательностью символов.
Если параметр не установлен, то проверка пароля в процессе аутентификации регистронезависима.
Использование ограничений на пароли пользователей информационной базы не влияет на существующие пароли. Ограничения будут применены только при изменении существующего пароля или при добавлении нового пользователя информационной базы.
Показать
michmich; Kinestetik; Дмитрий74Чел; Dementor; +4 Ответить
8. Dementor 1015 05.02.19 12:41 Сейчас в теме
(6) вот только про эту настройку знают единицы. За более чем десятилетнюю практику видел использование такой настройки только один раз. На крупных компаниях применяют доменную авторизацию, а в мелких предпочитают использовать стандартные пароли: "1", "123"... или вообще входят без паролей (если в базе только директор и главбух).
7. qwinter 671 05.02.19 09:54 Сейчас в теме
Выход, как мы видим, существует. Тут можно написать поисковую функцию с перепроверкой результата. Еще можно вместо поиска перед основным алгоритмом создать соответствие, где по строковым ключам загнать значение соответствующих ссылок. Но хотелось бы применять подобные костыли реже.
Зачем такие сложности? Если очень надо храните двоичные данные строки в строковом реквизите. Это элементарный код. Функции ПолучитьДвоичныеДанныеИзСтроки, ПолучитьДвоичныеДанныеИзHexСтроки и ПолучитьСтрокуИзДвоичныхДанных спасут ваш мир)))
9. Dementor 1015 05.02.19 12:43 Сейчас в теме
(7) тоже была такая идея, но не стал использоваться - хотел оставить для пользователя нормальную видимость.
10. qwinter 671 05.02.19 13:22 Сейчас в теме
(9) может я конечно чего то не учитываю, но не совсем понимаю проблемы сделать для пользователя нормальную видимость.
12. qwinter 671 05.02.19 13:45 Сейчас в теме
(9) Единственный минус, если поле слишком длинное, то индексировать не получиться. Максимальная срока 630 символов при котором поле 1с индексируется, а это получается 157 символов для поля с регистром. Так что реквизит формы желательно будет ограничить, если будет требоваться получать список выбора по полю.
11. qwinter 671 05.02.19 13:36 Сейчас в теме
(9) На форме
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
	
	НаименованиеСРегистром = ПолучитьСтрокуИзДвоичныхДанных(ПолучитьДвоичныеДанныеИзHexСтроки(ТекущийОбъект.ПолеДД));
	
КонецПроцедуры

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	
	ТекущийОбъект.ПолеДД = ПолучитьДвоичныеДанныеИзСтроки(НаименованиеСРегистром);
	
КонецПроцедуры
Показать

И если требуется в модуле менеджера, что бы выводить поле в представление или что бы подбор с регистром работал
Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
	
	СтандартнаяОбработка = Ложь;
	Представление = ПолучитьСтрокуИзДвоичныхДанных(ПолучитьДвоичныеДанныеИзHexСтроки(Данные.ПолеДД));
	
КонецПроцедуры

Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
	
	СтандартнаяОбработка = Ложь;
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 10
		|	Города.Ссылка КАК Ссылка
		|ИЗ
		|	Справочник.Города КАК Города
		|ГДЕ
		|	Города.ПолеДД ПОДОБНО &ПолеДД";
	
	Запрос.УстановитьПараметр("ПолеДД", Строка(ПолучитьДвоичныеДанныеИзСтроки(Параметры.СтрокаПоиска)) + "%");
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Выборка = РезультатЗапроса.Выбрать();
	
	ДанныеВыбора = Новый СписокЗначений;
	Пока Выборка.Следующий() Цикл
		ДанныеВыбора.Добавить(Выборка.Ссылка);
	КонецЦикла;
	
КонецПроцедуры

Процедура ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)
	
	СтандартнаяОбработка = Ложь;
	Поля.Добавить("ПолеДД");
	
КонецПроцедуры

Показать
14. Dementor 1015 06.02.19 11:28 Сейчас в теме
(11) для поля наименования покатит (если представление по наименованию) и в динамических списках выводить не Наименование, а Ссылка. А что с реквизитами? На формах списков/выборов писать варианты ПриПолученииДанных (для ОФ и УФ по разному) и делать функции общих модулей для расчета представления полей в отчетах на компоновке? Как-то уж слишком большая цена за возможность регистрозависимого поиска - дешевле в модуле менеджера справочника дописать свою поисковую функцию.
user720385; +1 Ответить
15. qwinter 671 06.02.19 13:52 Сейчас в теме
(14)
А что с реквизитами? На формах списков/выборов писать варианты ПриПолученииДанных (для ОФ и УФ по разному
Зачем вообще такой реквизит нужен, если по нему не делается ввод по строке? Или не делается поиск в формах списка/выбора? Искать по наименованию в модулях? Я промолчу, что я об этом думаю.
делать функции общих модулей для расчета представления полей в отчетах на компоновке?
Зачем? Эти функции можно использовать в вычисляемых полях.
дешевле в модуле менеджера справочника дописать свою поисковую функцию.
Считывание лишних данных всегда дороже. К тому же отсутствие возможности создания поиска в формах списка/выбора.
17. SeiOkami 3423 08.02.19 09:13 Сейчас в теме
А как сделать так, чтобы отборы СКД и динамических списков у пользователей "чувствительно" отрабатывали?
18. Dementor 1015 10.02.19 14:50 Сейчас в теме
(17) к счастью, класс задач с чувствительностью к регистру не очень широкий.
В тех случаях, когда нужно на формах делать регистрочувствительный фильтр - нужно делать этот фильтр самому. В зависимости от данных есть разные пути. Для небольшой выборки, когда отклонений много - запросом и повторным сравнением отобрать нужные ссылки и наложить на динамический список отбор по Ссылка ВСписке. Если выборка большая и мало отклонений - оставить Реквизит Равно/Подобно/Содержит, а с помощью функции отобрать именно отклонения для второго условия отбора - Ссылка НеВСписке.
20. God_loki 4 07.12.20 13:13 Сейчас в теме
(18) Широкий-неширокий, но я вот с такой столкнулся сегодня:
В ftp-папке ищу по маске "*.pdf" файлы и не нахожу, а выясняется, что у них всех расширение "*.PDF". И получается, чтобы найти все PDF файлы в папке нужно сначала искать так:
FTPСоединение.НайтиФайлы("*.PDF");
потом так:
FTPСоединение.НайтиФайлы("*.pdf");
а для верняка потом ещё так, так и так:
FTPСоединение.НайтиФайлы("*.Pdf");
FTPСоединение.НайтиФайлы("*.pDf");
FTPСоединение.НайтиФайлы("*.pdF");
FTPСоединение.НайтиФайлы("*.PdF");

По мне - так это глумление над разработчиком.
В описании функции ни слова о чувствительности к регистру:

FTPСоединение (FTPConnection)
НайтиФайлы (FindFiles)
Синтаксис:

НайтиФайлы(<Путь>, <Маска>, <ИскатьВПодкаталогах>)
Параметры:

<Путь> (обязательный)

Тип: Строка.
Путь к каталогу, в котором производится поиск. При использовании этой схемы в адресах необходимо указывать прямые слеши '/', а не обратные '\'.
Допускается указание полного имени файла (путь + имя).
<Маска> (необязательный)

Тип: Строка.
Маска выбора файлов. В строке маски допускается использование символа "*" (звездочка), обозначающего любое число произвольных символов, и "?" (знак вопроса), обозначающего один произвольный символ.
Если параметр задан, то первый параметр воспринимается системой как путь к каталогу, в котором требуется найти файлы, удовлетворяющие маске выбора.
21. japopov 68 22.09.21 10:43 Сейчас в теме
(20) а вот тут уже надо глядеть не в сторону 1С, а в сторону ОС, ведь Вы же ищете файлы ВНЕ базы 1С, а в файловой системе.
Вангую, что Ваш FTP-сервер под Linux, верно? Всё просто: в Linux имена файлов регистрозависимы, а в Windows - нет. И уже платформа 1С просто использует системную функцию для поиска файлов... Вот и результат.
Правда, это не имеет отношения к описанным в статье чудесам при поиске ВНУТРИ базы 1С.
user720385; Dementor; +2 Ответить
Оставьте свое сообщение