PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » Программирование на PureBasic » Ссылки на группы в регулярном выражении


Ссылки на группы в регулярном выражении

Сообщений 1 страница 4 из 4

1

Из предложенных вариантов использовал 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)

0

2

AZJIO написал(а):

7. RegexReplace1 и RegexReplace3 у меня вообще ошибку выдают

Я об этом писал, что в новых версиях перестало работать.

использовал $ в строковых переменных, чтобы было явно видно

И зачем эта архаика и возврат к мрачному прошлому, когда в Бейсике не было описания типов переменных?

AZJIO написал(а):

Но можно предположить что в тексте \3 может оказаться текстом, а не группой, как разруливать такой вариант? В AutoIt3 в этом случае предупреждает, если вы хотите избежать этой проблемы, то указывайте группы как \{3}, то есть вероятность такой комбинации в тексте более маловероятна

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

0

3

Smitis написал(а):

И зачем эта архаика и возврат к мрачному прошлому, когда в Бейсике не было описания типов переменных?

т.е. перейти на венгерскую нотацию?

0

4

AZJIO написал(а):

т.е. перейти на венгерскую нотацию?

Зачем?

П.С.
Хотя со временем я венгерскую нотацию стал использовать всё больше. Правда, в своём первоначальном варианте, который теперь называется "для приложений"
http://accwin.narod.ru/txt/01_h_notation.htm

0


Вы здесь » PureBasic - форум » Программирование на PureBasic » Ссылки на группы в регулярном выражении