Регулярки, пауза, архивы и хеш в 1С: какой самописный код уже можно заменить штатным и где это не сработает
Иван Недомолков · Dərc edilib:
Типичная картина в живой конфигурации: строку проверяют циклом по КодСимвола, паузу делают пустым циклом по ТекущаяДата(), архив распаковывают через 7z.exe, а ради чтения таблицы поднимают Excel.Application. Всё это когда-то было единственным способом. Сейчас почти у каждого такого места есть штатная замена, и часть из них появилась совсем недавно, в 8.3.22-8.3.27.
Вопрос “можно ли выкинуть самописное” упирается не в версию платформы и почти никогда не в режим совместимости. Он упирается в то, где исполняется строка: на сервере, в толстом клиенте или в тонком. Ниже справочник по двадцати заменам, правило выбора и два прогона по типовым конфигурациям, на которых видно, сколько из найденного на самом деле меняется одной строкой.
Короткий ответ
- Строка исполняется на сервере или в толстом клиенте, платформа 8.3.27: почти всё из таблицы ниже меняется на месте.
- Строка в тонком клиенте или в модуле
КлиентСервер: регулярок,ВызватьПаузу, хеширования,КодироватьСтроку, генератора паролей и чтения xlsx там нет. Замена возможна только через серверный вызов, то есть это уже переделка. - Режим совместимости новинки 8.3.22-8.3.27 не прячет. Мы проверили это исполнением в базе с режимом 8.3.17 на платформе 8.3.27: регулярка, пауза, генератор паролей,
ЧтениеФайлаАрхиваиWebSocketКлиентыотработали. Исключение одно: побитовые функции при режиме 8.3.10 и ниже.
Карта замен: что было и чем заменить
Версия - с какой платформы есть штатное средство. Доступность взята из синтакс-помощника 8.3.27, каждая замена вызвана кодом на тестовой базе 8.3.27.1606, кроме буфера обмена: его на сервере нет, и проверка там сводится к тому, что серверная компиляция отвечает “Переменная не определена”.
| Самописный код | Штатная замена | С версии | Чего нет |
|---|---|---|---|
VBScript.RegExp, компонента регулярок | СтрНайтиПоРегулярномуВыражению и ещё три функции | 8.3.23 | тонкий и веб-клиент |
| посимвольный цикл проверки или чистки строки | СтрПодобнаПоРегулярномуВыражению, СтрЗаменитьПоРегулярномуВыражению | 8.3.23 | тонкий и веб-клиент |
| компонента WebSocket | объект конфигурации “WebSocket-клиент”, WebSocketКлиенты | 8.3.27 | тонкий клиент |
| пауза пустым циклом или ping | ВызватьПаузу(Миллисекунды) | 8.3.25 | клиент и серверный вызов с клиента |
7z.exe, unrar через ЗапуститьПриложение | ЧтениеФайлаАрхива: GZIP, RAR, 7-ZIP, XZ, TAR | 8.3.26 | упаковки в эти форматы |
буфер обмена через ClipboardData HTML-поля | СредстваБуфераОбмена | 8.3.24 | сервер |
пароль на ГенераторСлучайныхЧисел | ГенераторСлучайныхПаролей | 8.3.22 | тонкий клиент |
| свой MD5, SHA, CRC32 | ХешированиеДанных | 8.3.1 (SHA256 с 8.3.3) | тонкий клиент |
| свой Base64 | Base64Строка, Base64Значение | 8.0 | - |
ADODB.Stream ради кодировки | ПолучитьДвоичныеДанныеИзСтроки с кодировкой | 8.3.10 | - |
MSXML2.XMLHTTP | HTTPСоединение, HTTPЗапрос | 8.0 | веб-клиент |
MSXML2.DOMDocument | ЧтениеXML, ПостроительDOM | 8.0 | - |
Scriptlet.TypeLib ради GUID | Новый УникальныйИдентификатор | 8.0 | - |
Scripting.FileSystemObject | КопироватьФайл, НайтиФайлы, УдалитьФайлы | 8.0 | - |
WIA.ImageFile и компоненты ресайза | ОбрабатываемаяКартинка | 8.3.14 | тонкий клиент |
Excel.Application ради значений | ТабличныйДокумент.Прочитать и Записать в xlsx | 8.3.6 | Прочитать в тонком клиенте |
ScriptControl ради JSON | ПрочитатьJSON, ЗаписатьJSON | 8.3.6 | - |
свои ПобитовоеИ, ПобитовоеИли | одноимённые функции платформы | 8.3.11 | режим совместимости 8.3.10 и ниже |
своя URLEncode | КодироватьСтроку с КодировкаURL | 8.3.1 | тонкий клиент |
| компонента под любую задачу выше | штатный объект этой задачи | - | смотреть, что компонента делает на деле |
Последняя строка самая скользкая: имя компоненты часто обещает одно, а внутри другое. Её надо открыть глазами, прежде чем выбрасывать.
Сначала узнайте, где исполняется строка
Все главные новинки последних версий живут на сервере и в толстом клиенте. Тонкий клиент их не получил. Отсюда простой порядок проверки для каждой находки:
- Директива процедуры.
&НаСервереи&НаСервереБезКонтекста- замена на месте.&НаКлиенте- смотрите столбец “Чего нет”. - Общий модуль. Флажки “Сервер”, “Клиент (управляемое приложение)”, “Вызов сервера” в свойствах модуля. Модуль с флажками и клиента, и сервера (по соглашению у него суффикс
КлиентСервер) исполняется и там, и там, поэтому регулярка в нём упадёт на клиенте. - Откуда вызывается серверный код.
ВызватьПаузубросает исключение в серверном вызове, пришедшем с клиента. Её место - фоновые и регламентные задания, HTTP- и веб-сервисы.
Если строка клиентская, вариантов два: вынести проверку в серверный вызов или оставить как есть. Серверный вызов ради одной проверки строки при вводе - это лишний сетевой круг на каждое нажатие, и иногда старый цикл честно лучше. Решение принимается по месту, а не правилом.
Режим совместимости: что он прячет на самом деле
Расхожее мнение такое: режим совместимости прячет от кода всё, что появилось позже него. Если бы это было так, конфигурация в режиме 8.3.10 не видела бы ни регулярок, ни паузы.
Проверка исполнением показывает другое. В базе с режимом 8.3.17 на платформе 8.3.27:
| Вызов | Появился | Результат в режиме 8.3.17 |
|---|---|---|
СтрПодобнаПоРегулярномуВыражению | 8.3.23 | работает |
ВызватьПаузу(200) | 8.3.25 | 204 мс |
Новый ГенераторСлучайныхПаролей | 8.3.22 | пароль из 12 символов |
Новый ЧтениеФайлаАрхива | 8.3.26 | объект создан |
WebSocketКлиенты | 8.3.27 | менеджер клиентов |
Режим прячет то, у чего в списке изменений платформы стоит оговорка “в режиме совместимости поведение не изменилось”. В линейке 8.3.22-8.3.27 у новых функций такой оговорки нет. Есть она у побитовых функций 8.3.11, и поэтому в типовой с режимом 8.3.10 свои ПобитовоеИ и ПобитовоеИли компилируются, а внешняя обработка с той же функцией на базе без режима не создаётся с ошибкой “Процедура или функция с указанным именем уже определена (ПобитовоеИ)”.
Базы с режимом ровно 8.3.10 под рукой не было, так что честный предел вывода такой: в режиме 8.3.17 новинки видны, и в списке изменений нет оговорки, которая спрятала бы их при режиме ниже.
Рецепты: было и стало
Проверка строки регуляркой
// Было: цикл по символам
Для Поз = 1 По СтрДлина(Код) Цикл
Если СтрНайти("0123456789", Сред(Код, Поз, 1)) = 0 Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
// Стало: сервер или толстый клиент, 8.3.23+
Возврат СтрПодобнаПоРегулярномуВыражению(Код, "[0-9]+");
Три детали, каждая проверена прогоном:
СтрПодобнаПоРегулярномуВыражениюсверяет строку целиком. “12а” и “а12” по шаблону[0-9]+дают Ложь, якоря^и$не нужны.\dв этом движке (ICU) принимает и цифры других алфавитов, например арабские. Цикл по кодам 48-57 их отвергал. Для ИИН, БИН, кодов и номеров пишите[0-9].- На пустой строке цикл возвращает Истина, а
[0-9]+- Ложь. Если пустое значение допустимо, шаблон[0-9]*.
Проверка ИИН целиком, 12 цифр:
ЭтоИИН = СтрПодобнаПоРегулярномуВыражению(Строка, "[0-9]{12}");
Функций с регулярками в платформе четыре: найти, найти все, заменить и “подобна”. Функции разделения строки по регулярке нет, хотя по аналогии её легко ожидать: вызов отвечает “Процедура или функция с указанным именем не определена”.
Пауза
// Было: процессор крутит пустой цикл всё время ожидания
ВремяЗавершения = ТекущаяДата() + 2;
Пока ТекущаяДата() < ВремяЗавершения Цикл
КонецЦикла;
// Стало: фоновое задание, HTTP-сервис, 8.3.25+
ВызватьПаузу(2000); // аргумент в миллисекундах
ВызватьПаузу(300) в HTTP-сервисе заняла 310 мс. На клиенте замена другая: ПодключитьОбработчикОжидания("ПродолжитьПослеПаузы", Секунд, Истина). Синхронная пауза превращается в продолжение, и вызывающий код переписывается целиком.
Распаковка архива
// Было
ЗапуститьПриложение("""C:\Program Files\7-Zip\7z.exe"" x """ + Архив + """", , Истина);
// Стало: 8.3.26+, тонкий и толстый клиент, сервер
Чтение = Новый ЧтениеФайлаАрхива(Архив);
Чтение.ИзвлечьВсе(Каталог);
Чтение.Закрыть();
Проверено на gzip: файл извлёкся, кириллица в тексте цела. RAR, 7-ZIP, XZ и TAR взяты из списка изменений. Платформа эти форматы только читает. Если 7z.exe в коде нужен для упаковки, замены нет. И ещё одно: ЧтениеZipФайла и ЗаписьZipФайла с 8.3.26 объявлены устаревшими, писать новый код на них не стоит.
Хеш и контрольная сумма
Хеш = Новый ХешированиеДанных(ХешФункция.CRC32);
Хеш.Добавить(ДвоичныеДанные);
Црц = Хеш.ХешСумма;
Самописный CRC32 одного мегабайта на встроенном языке занимал 6,3-7,4 секунды, штатный - около миллисекунды, на пределе точности таймера, суммы совпали. SHA-256 от 50 МБ штатно - 307 мс. Разница в тысячи раз, и никакая оптимизация цикла её не закроет. HMAC отдельной функцией в платформе нет: если код считает HMAC, заменяется хеш внутри, обвязка остаётся.
Буфер обмена
&НаКлиенте
Асинх Процедура КопироватьСсылку(Команда)
Если СредстваБуфераОбмена.ИспользованиеДоступно() Тогда
Ждать СредстваБуфераОбмена.ПоместитьДанныеАсинх(Ссылка);
КонецЕсли;
КонецПроцедуры
Методы асинхронные, процедура становится Асинх. На сервере объекта нет вовсе.
Генератор пароля и URL-кодирование
Генератор = Новый ГенераторСлучайныхПаролей;
Пароль = Генератор.СлучайныйПароль(12, Ложь); // Истина - запоминаемый
Кодированная = КодироватьСтроку(Строка, СпособКодированияСтроки.КодировкаURL);
Оба есть только на сервере и в толстом клиенте. Своя URLEncode в клиентском модуле появляется как раз поэтому, и там она может быть оправдана.
Что нашлось в двух типовых
Мы прогнали обе конфигурации Ревизором костылей: он разбирает код лексером, отличает код от комментария и строки, и по каждой находке смотрит, где исполняется строка.
Управление торговлей для Казахстана 3.4.4.87, режим совместимости 8.3.10. 7 157 модулей, 3,5 млн строк, проверка 223 секунды на сервере с включённой отладкой плюс 249 секунд выгрузки конфигуратором. 30 находок, каждую открыли глазами, верных 24.
| Вывод по верной находке | Сколько | Что это |
|---|---|---|
| замена на месте | 8 | 3 серверных цикла проверки строк, пауза (с переделкой вызова), распаковка 7z, 2 буфера обмена, генератор пароля |
| мешает тонкий клиент | 14 | 10 циклов в модулях КлиентСервер, 3 места с Excel, URLEncode |
| мешает режим 8.3.10 | 2 | свои ПобитовоеИ и ПобитовоеИли |
Шесть ложных находок поучительны сами по себе: четыре раза Excel создавался только ради проверки, что он установлен, или ради автофильтра в готовой книге, один раз 7za.exe упоминался в проверке установленного агента копирования, и один раз ScriptControl собирал массив COM, а не разбирал JSON. Все шесть пришли от правил уровня “На проверку”, которые судят по косвенным признакам. У правил уровня “Заменить”, где признак однозначный, верными оказались 4 находки из 4.
Бухгалтерия предприятия 3.0.204.22, платформа 8.3.27.2325, режим совместимости 8.3.27. 20 167 модулей, 17,4 млн строк, лексером разобрано 804 модуля. Выгрузка конфигуратором заняла около 55 минут, проверка 65. Эти находки вручную не размечались, ниже то, что выдал отчёт.
| Правило | Находок | Замена на месте |
|---|---|---|
| посимвольный цикл проверки или чистки строки | 71 | 19 |
| буфер обмена через HTML-поле или COM | 8 | 8 |
| свой Base64 | 7 | 7 |
| Excel через COM | 6 | 1 |
| свои побитовые функции | 6 | 6 |
| свой хеш или контрольная сумма | 2 | 0 |
| JavaScript через ScriptControl | 2 | 2 |
| компонента под закрытую задачу | 2 | 2 |
| пауза пустым циклом | 1 | 1 |
| Всего | 105 | 46 |
Две вещи видны сразу. Побитовые функции здесь меняются все шесть, потому что режим совместимости 8.3.27: та же находка, что в УТ упиралась в режим 8.3.10, в БП уходит одной правкой. А из 71 цикла по строкам на месте меняется только 19, остальные живут в клиентском и клиент-серверном коде. Тонкий клиент снова главная стена.
Отдельно о типовых: вендор держит такой код не по недосмотру. БСП обязана работать в тонком клиенте и в старых режимах совместимости. Переписывать типовую ради регулярок не нужно. Польза от карты в своих доработках, расширениях и внешних обработках, где режим и место исполнения выбираете вы.
Чего в платформе по-прежнему нет
Обратная проверка, тоже вызовом кода. Новый TCPСоединение, Новый СокетСервер, Новый UDPСоединение, Новый TCPСокет отвечают “Тип не определен”: произвольного TCP и UDP нет, слушающего сокета тоже. ЧтениеPDF по синтакс-помощнику умеет проверять подписи и доставать вложения, но не текст страниц. FileSystemObject, ADODB.Stream и MSXML на Linux-сервере взять неоткуда, хотя замена на встроенный язык для всех трёх давно есть.
Когда штатной функции нет, а работа сводится к циклу по байтам или символам большого объёма, выбор лежит между внешней компонентой и отдельным сервисом. Сколько компонента реально выигрывает и почему на 8.3.27 первым делом надо смотреть на параметр подключения, мы разобрали на замере 31 задачи.
Как пройти свой код
Руками это делается поиском по выгрузке, но поиск по подстроке тонет в комментариях, текстах сообщений и похожих именах. Ревизор костылей делает то же лексером: 20 правил из таблицы выше, по каждой находке модуль, строка, процедура и вывод “замена доступна”, “в тонком клиенте замены нет” или “нужна платформа новее”. Конфигурацию он выгружает сам пакетным конфигуратором или берёт готовую выгрузку, базу не меняет.
Если находок много и они в своих доработках, а переписывать некогда, напишите нам в WhatsApp: разберём отчёт, отделим замены на месте от тех, что требуют серверного вызова, и сделаем.