RDT1C/src/DataProcessors/ирОболочкаРегВыражение/Ext/ObjectModule.bsl
Администратор a796c44faf .
2025-06-01 19:11:00 +03:00

423 lines
27 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирКлиент Экспорт;
Перем ТекущийДвижок;
Перем Вычислитель;
Перем ТипВхождения;
Перем ВхождениеОбразец;
Перем ЧтениеJSON;
Перем СтарыйGlobal;
Перем СтарыйIgnoreCase;
Перем СтарыйMultiline;
Перем СтарыйPattern;
Перем ДоступныеДвижкиСтруктура;
Перем мВсеДвижки;
// Искать вхождения.
//
// Параметры:
// ТекстГдеИскать - Строка -
// ТолькоПоследнее - Булево - вернуть только последнее вхождение, имеет смысл при Global=Истина
// РазрешитьЧужуюКоллекцию - Булево - для ускорения
// выхЧислоВхождений - -
//
// Возвращаемое значение:
// Массив из ОбработкаОбъект.ирОболочкаРегВхождение - позиции указаны начиная с 0
//
Функция НайтиВхождения(Знач ТекстГдеИскать, ТолькоПоследнее = Ложь, РазрешитьЧужуюКоллекцию = Ложь, выхЧислоВхождений = 0, выхДлительность = Неопределено) Экспорт
_РежимОтладки = Ложь;
Вхождения = Новый Массив;
//Если ТекстГдеИскать = Неопределено Тогда
// ТекстГдеИскать = "";
//КонецЕсли;
Если ПустаяСтрока(ТекстГдеИскать) Тогда
Возврат Вхождения;
КонецЕсли;
выхЧислоВхождений = 0;
Если ТекущийДвижок = ВсеДвижки().VBScript Тогда
Если выхДлительность <> Неопределено Тогда
МоментНачала = ирОбщий.ТекущееВремяВМиллисекундахЛкс();
КонецЕсли;
РезультатПоиска = Вычислитель().Execute(ТекстГдеИскать);
Если выхДлительность <> Неопределено Тогда
выхДлительность = ирОбщий.ТекущееВремяВМиллисекундахЛкс() - МоментНачала;
КонецЕсли;
выхЧислоВхождений = РезультатПоиска.Count;
Если выхЧислоВхождений > 0 Тогда
Если ТолькоПоследнее Тогда
Вхождения.Добавить(РезультатПоиска.Item(РезультатПоиска.Count - 1));
Иначе
Если РазрешитьЧужуюКоллекцию Тогда
Вхождения = РезультатПоиска;
Иначе
Если _РежимОтладки Тогда // Можно менять на Истина в точке останова, например условием ирОбщий.Пр(_РежимОтладки, 1, 1)
// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
Для каждого Элемент из РезультатПоиска Цикл
Вхождения.Добавить(Элемент);
КонецЦикла;
Иначе
// Однострочный код использован для ускорения при разрешенной отладке. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика"
Для каждого Элемент из РезультатПоиска Цикл   Вхождения.Добавить(Элемент);   КонецЦикла;  
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
ИначеЕсли ТекущийДвижок = ВсеДвижки()._1С Тогда
Если выхДлительность <> Неопределено Тогда
МоментНачала = ирОбщий.ТекущееВремяВМиллисекундахЛкс();
КонецЕсли;
РезультатПоиска = Вычислить("СтрНайтиВсеПоРегулярномуВыражению(ТекстГдеИскать, Pattern, IgnoreCase, Multiline)");
Если выхДлительность <> Неопределено Тогда
выхДлительность = ирОбщий.ТекущееВремяВМиллисекундахЛкс() - МоментНачала;
КонецЕсли;
#Если Сервер И Не Сервер Тогда
РезультатПоиска = СтрНайтиВсеПоРегулярномуВыражению();
#КонецЕсли
выхЧислоВхождений = РезультатПоиска.Количество();
Если выхЧислоВхождений > 0 Тогда
Если ТипВхождения = Неопределено Тогда
ВхождениеОбразец = ирОбщий.СоздатьОбъектПоИмениМетаданныхЛкс("Обработка.ирОболочкаРегВхождение");
ТипВхождения = ТипЗнч(ВхождениеОбразец); // Надо удерживать ВхождениеОбразец, чтобы для внешней обработки ТипВхождения не разрушался
КонецЕсли;
Если ТолькоПоследнее Тогда
Элемент = РезультатПоиска[выхЧислоВхождений - 1];
РезультатПоиска = Новый Массив;
РезультатПоиска.Добавить(Элемент);
КонецЕсли;
Для каждого Элемент из РезультатПоиска Цикл
Вхождение = Новый (ТипВхождения);
#Если Сервер И Не Сервер Тогда
Вхождение = Обработки.ирОболочкаРегВхождение.Создать();
#КонецЕсли
Вхождение.FirstIndex = Элемент.НачальнаяПозиция - 1;
Вхождение.Length = Элемент.Длина;
Вхождение.Value = Элемент.Значение;
Группы = Новый Массив;
Если _РежимОтладки Тогда // Можно менять на Истина в точке останова, например условием ирОбщий.Пр(_РежимОтладки, 1, 1)
// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
Для Каждого Группа Из Элемент.ПолучитьГруппы() Цикл
Если Группа.НачальнаяПозиция = 0 Тогда
Группы.Добавить(Неопределено);
Иначе
Группы.Добавить(Группа.Значение);
КонецЕсли;
КонецЦикла;
Иначе
// Однострочный код использован для ускорения при разрешенной отладке. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика"
Для Каждого Группа Из Элемент.ПолучитьГруппы() Цикл   Если Группа.НачальнаяПозиция = 0 Тогда   Группы.Добавить(Неопределено);   Иначе   Группы.Добавить(Группа.Значение);   КонецЕсли;   КонецЦикла;  
КонецЕсли;
Вхождение.SubMatches = Группы;
Вхождения.Добавить(Вхождение);
КонецЦикла;
КонецЕсли;
Иначе
Если выхДлительность <> Неопределено Тогда
МоментНачала = ирОбщий.ТекущееВремяВМиллисекундахЛкс();
КонецЕсли;
Попытка
РезультатJSON = Вычислитель().НайтиСовпаденияJSON(ТекстГдеИскать);
Исключение
Если Истина
И Вычислитель <> Неопределено
И ЗначениеЗаполнено(Вычислитель.ОписаниеОшибки)
Тогда
ВызватьИсключение Вычислитель.ОписаниеОшибки; //@skip-check unknown-method-property
Иначе
ВызватьИсключение;
КонецЕсли;
КонецПопытки;
Если выхДлительность <> Неопределено Тогда
выхДлительность = ирОбщий.ТекущееВремяВМиллисекундахЛкс() - МоментНачала;
КонецЕсли;
Если ЗначениеЗаполнено(РезультатJSON) Тогда
УстановитьПривилегированныйРежим(Истина);
Если ТипВхождения = Неопределено Тогда
ВхождениеОбразец = ирОбщий.СоздатьОбъектПоИмениМетаданныхЛкс("Обработка.ирОболочкаРегВхождение");
ТипВхождения = ТипЗнч(ВхождениеОбразец); // Надо удерживать ВхождениеОбразец, чтобы для внешней обработки ТипВхождения не разрушался
КонецЕсли;
Если ЧтениеJSON = Неопределено Тогда
ЧтениеJSON = Вычислить("Новый ЧтениеJSON"); //
#Если Сервер И Не Сервер Тогда
ЧтениеJSON = Новый ЧтениеJSON;
#КонецЕсли
КонецЕсли;
ЧтениеJSON.УстановитьСтроку(РезультатJSON);
Коллекция = Вычислить("ПрочитатьJSON(ЧтениеJSON, Ложь)"); // см. ЗначениеИзСтрокиВнутр(РезультатJSON) - 8.3
выхЧислоВхождений = Коллекция.Количество();
Если выхЧислоВхождений > 0 Тогда
Если ТолькоПоследнее Тогда
Элемент = Коллекция[выхЧислоВхождений - 1];
Коллекция = Новый Массив;
Коллекция.Добавить(Элемент);
КонецЕсли;
Для Каждого Элемент Из Коллекция Цикл
Вхождение = Новый (ТипВхождения);
#Если Сервер И Не Сервер Тогда
Вхождение = Обработки.ирОболочкаРегВхождение.Создать();
#КонецЕсли
ЗаполнитьЗначенияСвойств(Вхождение, Элемент, "FirstIndex, Length, SubMatches, Value");
Вхождения.Добавить(Вхождение);
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЕсли;
//Если выхДлительность <> неопределено И выхДлительность > 50 Тогда
// Пустышка = 0; // Для отладки
//КонецЕсли;
Возврат Вхождения;
КонецФункции
// Заменить вхождения. Replace
Функция Заменить(Знач ТекстГдеИскать, Знач ШаблонЗамены) Экспорт
Если ПустаяСтрока(ТекстГдеИскать) Тогда
Возврат ТекстГдеИскать;
КонецЕсли;
Если ТекущийДвижок = ВсеДвижки()._1С Тогда
Результат = Вычислить("СтрЗаменитьПоРегулярномуВыражению(ТекстГдеИскать, Pattern, ШаблонЗамены, IgnoreCase, Multiline)");
ИначеЕсли ТекущийДвижок = ВсеДвижки().VBScript Тогда
Результат = Вычислитель().Replace(ТекстГдеИскать, ШаблонЗамены);
Иначе
Попытка
Результат = Вычислитель().Заменить(ТекстГдеИскать,, ШаблонЗамены);
Исключение
// После номера группы обязательно делать не цифру. Тогда будет работать одинаково в VBScript и PCRE2. Например вместо "$152" делать "$1 52", иначе PCRE2 будет читать "ссылка на группу 152"
Если ЗначениеЗаполнено(Вычислитель.ОписаниеОшибки) Тогда
ВызватьИсключение Вычислитель.ОписаниеОшибки; //@skip-check unknown-method-property
Иначе
ВызватьИсключение;
КонецЕсли;
КонецПопытки;
КонецЕсли;
Возврат Результат;
КонецФункции
// Test
Функция Проверить(Знач ТекстГдеИскать) Экспорт
Если ТекстГдеИскать = Неопределено Тогда
ТекстГдеИскать = "";
КонецЕсли;
Результат = Вычислитель().Test(ТекстГдеИскать);
Возврат Результат;
КонецФункции
Функция КоличествоГрупп(Вхождение) Экспорт
Если ТипЗнч(Вхождение.SubMatches) = Тип("Массив") Тогда
Результат = Вхождение.SubMatches.Количество();
Иначе
Результат = Вхождение.SubMatches.Count;
КонецЕсли;
Возврат Результат;
КонецФункции
Функция ДоступенPCRE2() Экспорт
Возврат ирКэш.НомерВерсииПлатформыЛкс() >= 803006;
КонецФункции
Функция ДоступенVBScript() Экспорт
Возврат ирКэш.ЛиПлатформаWindowsЛкс();
КонецФункции
Функция Доступен1СВычислитель() Экспорт
Возврат Истина
И ирКэш.НомерВерсииПлатформыЛкс() >= 803023
И ирКэш.НомерРежимаСовместимостиЛкс() >= 803009; // Недокументированное ограничение
КонецФункции
Функция ДоступныеДвижки(ВернутьСтруктуру = Истина) Экспорт
Если ВернутьСтруктуру И ДоступныеДвижкиСтруктура <> Неопределено Тогда
Возврат ДоступныеДвижкиСтруктура;
КонецЕсли;
Список = Новый СписокЗначений;
Структура = Новый Структура;
Если Доступен1СВычислитель() Тогда
Имя = ВсеДвижки()._1С;
Список.Добавить(Имя);
Структура.Вставить("_1С", Имя);
КонецЕсли;
Если ДоступенPCRE2() Тогда
// https://www.pcre.org/current/doc/html
// https://github.com/alexkmbk/RegEx1CAddin
Имя = ВсеДвижки().PCRE2;
Список.Добавить(Имя);
Структура.Вставить("PCRE2", Имя);
КонецЕсли;
Если ДоступенVBScript() Тогда
Имя = ВсеДвижки().VBScript;
Список.Добавить(Имя);
Структура.Вставить("VBScript", Имя);
КонецЕсли;
Если ВернутьСтруктуру Тогда
Результат = Структура;
ДоступныеДвижкиСтруктура = Структура;
Иначе
Результат = Список;
КонецЕсли;
Возврат Результат;
КонецФункции
Функция ВсеДвижки() Экспорт
Если мВсеДвижки <> Неопределено Тогда
Возврат мВсеДвижки;
КонецЕсли;
мВсеДвижки = Новый Структура;
мВсеДвижки.Вставить("_1С", "1С");
мВсеДвижки.Вставить("PCRE2", "PCRE2");
мВсеДвижки.Вставить("VBScript", "VBScript");
Возврат мВсеДвижки;
КонецФункции
Функция ТекущийДвижок() Экспорт
Возврат ТекущийДвижок;
КонецФункции
Функция УстановитьДвижок(НовыйДвижок) Экспорт
Если ТекущийДвижок = НовыйДвижок Тогда
Возврат Истина;
КонецЕсли;
Если НовыйДвижок = ВсеДвижки().PCRE2 Тогда
Если ДоступенPCRE2() Тогда
ТекущийДвижок = НовыйДвижок;
КонецЕсли;
ИначеЕсли НовыйДвижок = ВсеДвижки().VBScript Тогда
Если ДоступенVBScript() Тогда
ТекущийДвижок = НовыйДвижок;
КонецЕсли;
ИначеЕсли НовыйДвижок = ВсеДвижки()._1С Тогда
Если Доступен1СВычислитель() Тогда
ТекущийДвижок = НовыйДвижок;
КонецЕсли;
КонецЕсли;
Если ТекущийДвижок = НовыйДвижок Тогда
СтарыйGlobal = Неопределено;
СтарыйIgnoreCase = Неопределено;
СтарыйMultiline = Неопределено;
СтарыйPattern = Неопределено;
Вычислитель = Неопределено;
КонецЕсли;
Возврат ТекущийДвижок = НовыйДвижок;
КонецФункции
Функция Вычислитель()
Если Вычислитель = Неопределено Тогда
Если ТекущийДвижок = ВсеДвижки().VBScript Тогда
Вычислитель = Новый COMОбъект("VBScript.RegExp");
Иначе
мПлатформа = ирКэш.Получить();
#Если Сервер И Не Сервер Тогда
мПлатформа = Обработки.ирПлатформа.Создать();
#КонецЕсли
Вычислитель = мПлатформа.ПолучитьОбъектВнешнейКомпонентыИзМакета("RegEx", "AddIn.ВычислительРегВыражений.RegEx", "ВычислительРегВыражений", ТипВнешнейКомпоненты.Native); // ОбработкаОбъект.ирТипКомпонентаRegEx
Вычислитель.ВызыватьИсключения = Истина;
КонецЕсли;
КонецЕсли;
// Ускорение
Если СтарыйGlobal <> Global Тогда
Вычислитель.Global = Global;
СтарыйGlobal = Global;
КонецЕсли;
Если СтарыйIgnoreCase <> IgnoreCase Тогда
Вычислитель.IgnoreCase = IgnoreCase;
СтарыйIgnoreCase = IgnoreCase;
КонецЕсли;
Если СтарыйMultiline <> Multiline Тогда
Вычислитель.Multiline = Multiline;
СтарыйMultiline = Multiline;
КонецЕсли;
Если СтарыйPattern <> Pattern Тогда
Вычислитель.Pattern = Pattern;
СтарыйPattern = Pattern;
КонецЕсли;
Возврат Вычислитель;
КонецФункции
Функция НоваяТаблицаВхождений() Экспорт
//ТаблицаВхождений = Новый ТаблицаЗначений;
//ТаблицаВхождений.Колонки.Добавить("Номер", Новый ОписаниеТипов("Число"));
//ТаблицаВхождений.Колонки.Добавить("ТекстВхождения", Новый ОписаниеТипов("Строка"));
//ТаблицаВхождений.Колонки.Добавить("ПозицияВхождения", Новый ОписаниеТипов("Число"));
//ТаблицаВхождений.Колонки.Добавить("ДлинаВхождения", Новый ОписаниеТипов("Число"));
мПлатформа = ирКэш.Получить();
#Если Сервер И Не Сервер Тогда
мПлатформа = Обработки.ирПлатформа.Создать();
#КонецЕсли
ТаблицаВхождений = мПлатформа.ВхожденияРегВыражения.ВыгрузитьКолонки();
ТаблицаВхождений.Колонки.Удалить("Номер");
ТаблицаВхождений.Колонки.Удалить(ирОбщий.ПеревестиСтроку("НомерСтроки"));
ТаблицаВхождений.Колонки.Удалить("Группы");
ТаблицаВхождений.Колонки.Добавить("Группы"); // Массив из Строка, ОбработкаОбъект.ирОболочкаРегВхождение
//! ТаблицаВхождений.Колонки.Добавить("Группа0");
Возврат ТаблицаВхождений;
КонецФункции
Функция ОбработатьТекстОшибки(Знач ТекстОшибки, Знач Выражение) Экспорт
Если ТекущийДвижок = ВсеДвижки().VBScript Тогда
КодОшибкиВБСкрипт = ирОбщий.НайтиРегВыражениеЛкс(ТекстОшибки, "\(\w+\): Произошла исключительная ситуация \((\w+)\)");
Если КодОшибкиВБСкрипт.Количество() > 0 Тогда
КодОшибкиВБСкрипт = КодОшибкиВБСкрипт[0].Группа0;
КодыОшибокВБСкрипт = ПолучитьМакет("КодыОшибокVBScript");
КодыОшибокВБСкрипт = ирОбщий.ТаблицаЗначенийИзТабличногоДокументаЛкс(КодыОшибокВБСкрипт);
СтрокаТаблицы = КодыОшибокВБСкрипт.Найти(ВРег(КодОшибкиВБСкрипт), "Код");
Если СтрокаТаблицы <> Неопределено Тогда
ТекстОшибки = ирОбщий.СтрЗаменитьЛкс(ТекстОшибки, КодОшибкиВБСкрипт, " " + СтрокаТаблицы.Текст, Истина, Ложь);
КонецЕсли;
Если Найти(Выражение, "(?<") > 0 Тогда
ТекстОшибки = ТекстОшибки + Символы.ПС + ирОбщий.СтрШаблонЛкс("Вычислитель %1 не поддерживает элементы заглядывания назад - (?<", ТекущийДвижок);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат ТекстОшибки;
КонецФункции
//ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла);
//ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf";
//ирПортативный #Если Клиент Тогда
//ирПортативный Контейнер = Новый Структура();
//ирПортативный Оповестить("ирПолучитьБазовуюФорму", Контейнер);
//ирПортативный Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда
//ирПортативный ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля);
//ирПортативный ирПортативный.Открыть();
//ирПортативный КонецЕсли;
//ирПортативный #Иначе
//ирПортативный ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта
//ирПортативный #КонецЕсли
//ирПортативный ирОбщий = ирПортативный.ОбщийМодульЛкс("ирОбщий");
//ирПортативный ирКэш = ирПортативный.ОбщийМодульЛкс("ирКэш");
//ирПортативный ирСервер = ирПортативный.ОбщийМодульЛкс("ирСервер");
//ирПортативный ирКлиент = ирПортативный.ОбщийМодульЛкс("ирКлиент");
IgnoreCase = Истина;
ДоступныеДвижки = ДоступныеДвижки();
Если Доступен1СВычислитель() Тогда
// Ошибка платформы 8.3.24-25+ https://www.hostedredmine.com/issues/986747
ТекущийДвижок = ДоступныеДвижки._1С;
КонецЕсли;
Если ДоступенPCRE2() Тогда
// Плавающие зависания и сбои создания внешней компоненты https://devtool1c.ucoz.ru/forum/2-2783-1 , https://devtool1c.ucoz.ru/forum/2-2795-1
ТекущийДвижок = ДоступныеДвижки.PCRE2;
КонецЕсли;
// На сервере не используем из-за сильного замедления работы этого COM объекта в многопоточном окружении https://www.hostedredmine.com/issues/913592
#Если Клиент Тогда
Если ДоступенVBScript() Тогда
ТекущийДвижок = ДоступныеДвижки.VBScript;
КонецЕсли;
#КонецЕсли
//ТекущийДвижок = "1С"; // для отладки