//ирПортативный Перем ирПортативный Экспорт; //ирПортативный Перем ирОбщий Экспорт; //ирПортативный Перем ирСервер Экспорт; //ирПортативный Перем ирКэш Экспорт; //ирПортативный Перем ирКлиент Экспорт; Перем ТекущийДвижок; Перем Вычислитель; Перем ТипВхождения; Перем ВхождениеОбразец; Перем Чтение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С"; // для отладки