Regular expressions with links to groups

Everything else that doesn't fall into one of the other PB categories.
AZJIO
Addict
Addict
Posts: 1312
Joined: Sun May 14, 2017 1:48 am

Regular expressions with links to groups

Post by AZJIO »

Using other people's examples, I made changes
+Once
module by eddy

Code: Select all

EnableExplicit

#RegExp = 0

Procedure.s RegexReplace2(RgEx, *Result.string, Replace0$)
	Protected i, CountGr, Pos, Offset = 1
	Protected Result$, Replace$
	Protected NewList item.s()
	Protected LenT, *Point ;, Count

	CountGr = CountRegularExpressionGroups(RgEx)
	; ограничение групп, только обратные ссылки \1 .. \9
	If CountGr > 9
		CountGr = 9
	EndIf

	If ExamineRegularExpression(RgEx, *Result\s)
		While NextRegularExpressionMatch(RgEx)
			Pos = RegularExpressionMatchPosition(RgEx)
			Replace$ = ReplaceString(Replace0$,"\0", RegularExpressionMatchString(RgEx)) ; обратная ссылка \0
			For i = 1 To CountGr
				Replace$ = ReplaceString(Replace$, "\"+Str(i), RegularExpressionGroup(RgEx, i))
			Next
			; item() = часть строки между началом и первым совпадением или между двумя совпадениями + результат подстановки групп
			
			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())
		LenT = 0
		ForEach item()
			LenT + Len(item()) ; вычисляем длину данных для  вмещения частей текста
		Next
		
		*Result\s = Space(LenT) ; создаём строку забивая её пробелами
		*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
AZJIO
Addict
Addict
Posts: 1312
Joined: Sun May 14, 2017 1:48 am

Re: Regular expressions with links to groups

Post by AZJIO »

The previous example has problems. Look at the last 2 tests that do not work correctly in the previous code. In the new code, I am looking for the positions of the groups and will replace by positions from the end to the beginning.

I also wanted to add a search for groups in this form \{11}, which would allow to have more groups and more accurately identify. That is, if such groups are found, then ignore the \1 syntax.

Code: Select all

EnableExplicit

Structure ReplaceGr
  pos.i
  ngr.i
  group.s
EndStructure


; https://www.purebasic.fr/english/viewtopic.php?p=575871
Procedure RegexReplace2(RgEx, *Result.string, Replace0$)
	Protected i, CountGr, Pos, Offset = 1
	Protected Replace$
	Protected NewList item.s()
	Protected LenT, *Point
; 	Static RE2
	Protected RE2
	Protected NewList ReplaceGr.ReplaceGr()

	CountGr = CountRegularExpressionGroups(RgEx)
	; ограничение групп, только обратные ссылки \1 .. \9
	If CountGr > 9
		CountGr = 9
	EndIf

	If ExamineRegularExpression(RgEx, *Result\s)
		
		; Поиск ссылок на группы в поле замены в регвыр
; 		If Not RE2 ; вариант для Static, но неуниверсальность в отдельной функции удаления регвыра
; 			RE2 = CreateRegularExpression(#PB_Any, "\\\d")
; 		EndIf
		RE2 = CreateRegularExpression(#PB_Any, "\\\d")
		If RE2
			If ExamineRegularExpression(RE2, Replace0$)
				While NextRegularExpressionMatch(RE2)
					If AddElement(ReplaceGr())
						ReplaceGr()\pos = RegularExpressionMatchPosition(RE2) ; позиция
						ReplaceGr()\ngr = ValD(Right(RegularExpressionMatchString(RE2), 1)) ; номер группы
						ReplaceGr()\group = RegularExpressionMatchString(RE2) ; текст группы
					EndIf
				Wend
			EndIf
			FreeRegularExpression(RE2) ; убрать строку при Static
		EndIf
		If Not ListSize(ReplaceGr())
			*Result\s = ReplaceRegularExpression(RgEx, *Result\s, Replace0$)
			ProcedureReturn
		EndIf
; 		Сортировка по позиции, чтобы делать замены с конца и не нарушались ранее найденные позиции
		SortStructuredList(ReplaceGr(), #PB_Sort_Descending, OffsetOf(ReplaceGr\pos), TypeOf(ReplaceGr\pos))

		While NextRegularExpressionMatch(RgEx)
			Pos = RegularExpressionMatchPosition(RgEx)
			Replace$ = Replace0$

			ForEach ReplaceGr()
				If ReplaceGr()\ngr
					Replace$ = ReplaceString(Replace$, ReplaceGr()\group, RegularExpressionGroup(RgEx, ReplaceGr()\ngr), #PB_String_NoCase, ReplaceGr()\pos, 1)
				Else
					Replace$ = ReplaceString(Replace$, ReplaceGr()\group, RegularExpressionMatchString(RgEx), #PB_String_NoCase, ReplaceGr()\pos, 1) ; обратная ссылка \0
				EndIf
			Next
			; item() = часть строки между началом и первым совпадением или между двумя совпадениями + результат подстановки групп
			
			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())
		LenT = 0
		ForEach item()
			LenT + Len(item()) ; вычисляем длину данных для  вмещения частей текста
		Next
		
		*Result\s = Space(LenT) ; создаём строку забивая её пробелами
		*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

Text\s = "\2aa"
CreateRegularExpression(#RegExp , "(\D+\d+)(\D+)" )
RegexReplace2(#RegExp, @Text, "\2\1" )
FreeRegularExpression(#RegExp)
Debug Text\s

Text\s = "\2aa"
CreateRegularExpression(#RegExp , "(\D+\d+)(\D+)" )
RegexReplace2(#RegExp, @Text, "\0\2" )
FreeRegularExpression(#RegExp)
Debug Text\s

Post Reply