Из предложенных вариантов использовал RegexReplace2 как компактную и вполне выдавала ожидаемое, но столкнулся с проблемой
#RegExp = 0 Define Path$ = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\7-Zip\7-Zip File Manager" CreateRegularExpression(#RegExp , "(^.{3,11}/|.{11})(.*)(/.{6,27}|.{27})$" ) Debug RegexReplace2(#RegExp, Path$, "\1...\3" )
выдаёт "C:\ProgramD...ms-Zip-Zip File Manager", то есть в пути \7 была удалена как 7 группа. Начал изучать функцию, в итоге некоторая оптимизация:
EnableExplicit #RegExp = 0 Procedure.s RegexReplace2(RgEx, *Result.string, Replace1$) Protected i, CountGr, Pos, Offset = 1 Protected Result$, Replace$ Protected NewList item.s() Protected Count, Len, *Point CountGr = CountRegularExpressionGroups(RgEx) ; Debug CountGr If CountGr > 9 CountGr = 9 EndIf ; ограничение групп, только обратные ссылки \1 .. \9 Protected re, MaxGr = -1, tmp ; Здесь ищем максимальное число групп указанных в тексте замены и соответственно не обрабатываем группы больше максимальной re = CreateRegularExpression(#PB_Any, "\\(\d)" ) ; Проверять правильность не нужно так как это внутренняя функция If ExamineRegularExpression(re, Replace1$) While NextRegularExpressionMatch(re) tmp = Asc(RegularExpressionMatchString(re)) - 48 If tmp > MaxGr MaxGr = tmp EndIf Wend EndIf ; Если число групп например 7, а в замене максимальная группа 4, то обрабатываем в цикле до 4, а не до 7 If CountGr > MaxGr CountGr = MaxGr EndIf If ExamineRegularExpression(RgEx, *Result\s) While NextRegularExpressionMatch(RgEx) Pos = RegularExpressionMatchPosition(RgEx) Replace$ = ReplaceString(Replace1$,"\0", RegularExpressionMatchString(RgEx)) ; обратная ссылка \0 For i = 1 To CountGr Replace$ = ReplaceString(Replace$, "\"+Str(i), RegularExpressionGroup(RgEx, i)) Next ; Result$ + часть строки между началом и первым совпадением или между двумя совпадениями + результат подстановки групп If AddElement(item()) item() = Mid(*Result\s, Offset, Pos - Offset) + Replace$ EndIf Offset = Pos + RegularExpressionMatchLength(RgEx) Wend If AddElement(item()) item() = Mid(*Result\s, Offset) EndIf ; Формирования текстового списка ; Debug "Count = " + Str(ListSize(item())) Count = ListSize(item()) Len=0 ForEach item() Len + Len(item()) ; вычисляем длину данных для вмещения частей текста Next *Result\s = Space(Len) ; создаём строку забивая её пробелами *Point = @*Result\s ; Получаем адрес строки ForEach item() CopyMemoryString(item(), @*Point) ; копируем очередной путь в указатель Next ; Конец => Формирования текстового списка FreeList(item()) ; удаляем список, хотя в функции наверно это не требуется EndIf EndProcedure #RegExp = 0 Define Text.string Text\s = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\7-Zip\7-Zip File Manager" CreateRegularExpression(#RegExp , "(^.{3,11}/|.{11})(.*)(/.{6,27}|.{27})$" ) RegexReplace2(#RegExp, @Text, "\1...\3" ) FreeRegularExpression(#RegExp) Debug Text\s Text\s = "56868797689645" CreateRegularExpression(#RegExp , "(\A\d{1,3}(?=(\d{3})+\z)|\d{3}(?=\d))" ) RegexReplace2(#RegExp, @Text, "\1 " ) FreeRegularExpression(#RegExp) Debug Text\s
Что здесь есть?
1. Функция CountRegularExpressionGroups() была внутри цикла, но она из ID регвыра выдаёт группы, то есть не найденное, а по количеству скобок в регулярном выражении, ведь оно выдаёт это число не после того как что-то найдёт, а анализируя регвыр. То есть вытащил из цикла и поставил выше.
2. Там было удаление ссылок на несуществующие группы, то есть если в регвыр 3 группы, а в строке встречается \7, то удаляем \7 так как таких групп нет. Но автор регвыра скорее всего значет число групп в регвыре и правильно указывает ссылки и вряд ли укажет число группы, которой нет в регвыр, поэтому удаление ссылок скорее всего удалить обычный текст.
For GroupNumber=GroupCount+1 To 9 ; отсутствующие группы на пустые строки Replacing = ReplaceString(Replacing,"\"+Str(GroupNumber),"") Next
Но можно предположить что в тексте \3 может оказаться текстом, а не группой, как разруливать такой вариант? В AutoIt3 в этом случае предупреждает, если вы хотите избежать этой проблемы, то указывайте группы как \{3}, то есть вероятность такой комбинации в тексте более маловероятна, ну и к тому же это позволяет указать группы более 9, например \{45}, в противном случае это бы воспринималась как группа 4, а 5 как текст.
3. Изначально, когда я не понял суть функции RegexReplace2 я посчитал, что функция обрабатывает 9 групп несмотря на то, что у меня в регвыре 3 группы и ссылка на \3 максимальная. Решил, что надо в тексте замены найти максимальный номер группы и добавил блок с переменной MaxGr отделённый пустыми строками, его в принципе можно удалить, так как выяснилось что CountRegularExpressionGroups выдаёт то что нужно, и нет смысла искать максимальную ссылку, потому что если регвыр составлен правильно, то никто не будет плодить группы, которые не используются, так как их можно пометить как (?:...) - группа которая не возвращается в виде ссылки на группу, а используется например для выбора ИЛИ, например (?:ъ|ь). Оставил этот блок для примера, но его надо убрать.
4. Переименовал переменные, счётчик в цикле заменил на "i", использовал $ в строковых переменных, чтобы было явно видно.
5. Объединение строк сделал через работу с памятью, иначе на больших текста это будет работать медленно.
6. RegexReplace1 и RegexReplace3 у меня вообще ошибку выдают, может проблема 32 бит или ANSI?
Отредактировано AZJIO (14.10.2021 12:41:53)