Analyzer of brackets (?)

Just starting out? Need help? Post your questions and find answers here.
AZJIO
Addict
Addict
Posts: 2171
Joined: Sun May 14, 2017 1:48 am

Analyzer of brackets (?)

Post by AZJIO »

My brain has broken. How to do it?

Code: Select all

EnableExplicit

Procedure Brackets(*c.Character, Array ArrBrackets(2))
	Protected c, i, Pos = -1, Open, Close, flgBracket
	If *c = 0 Or *c\c = 0
		ProcedureReturn 0
	EndIf

	While *c\c
		Pos + 1
		Select *c\c
			Case '('
				Open + 1
				ReDim ArrBrackets(1, Open)
				If flgBracket
					c + 1
				EndIf
				ArrBrackets(0, Open) = Pos
				flgBracket = 1
			Case ')'
				Close + 1
				If c
					ArrBrackets(1, Close + c - 1) = Pos
					c - 1
				Else
					ArrBrackets(1, Close) = Pos
				EndIf
				flgBracket = 0
		EndSelect
		*c + SizeOf(Character)
	Wend
EndProcedure

Define MyStr$, i
Define Dim ArrBr(1, 0)

MyStr$ = "word (word) (word\(f\)word) (word(f)word)"
Brackets(@MyStr$, ArrBr())

Debug "Count = " + Str(ArraySize(ArrBr(), 2))
For i = 0 To ArraySize(ArrBr(), 2) - 1
	Debug Str(ArrBr(0, i)) + " - " + Str(ArrBr(1, i))
Next

Enumeration
    #Brackets1
    #Brackets2
EndEnumeration

Define *Text
Define Toggle

If Not InitScintilla()
    End
EndIf

If OpenWindow(0, 0, 0, 630, 190, "ScintillaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	ScintillaGadget(0, 10, 10, 620, 170, 0)
	*Text = UTF8(MyStr$)
	ScintillaSendMessage(0, #SCI_SETTEXT, 0, *Text)
	FreeMemory(*Text)
	ScintillaSendMessage(0, #SCI_STYLESETSIZE, #STYLE_DEFAULT, 16) 
	
	ScintillaSendMessage(0, #SCI_INDICSETSTYLE, #Brackets1, #INDIC_STRAIGHTBOX) 
	ScintillaSendMessage(0, #SCI_INDICSETFORE, #Brackets1, $9900FF)				
	ScintillaSendMessage(0, #SCI_INDICSETUNDER, #Brackets1, 1)						  
	ScintillaSendMessage(0, #SCI_INDICSETALPHA, #Brackets1, 127)					  
	
	ScintillaSendMessage(0, #SCI_INDICSETSTYLE, #Brackets2, #INDIC_STRAIGHTBOX) 
	ScintillaSendMessage(0, #SCI_INDICSETFORE, #Brackets2, $0099FF)				
	ScintillaSendMessage(0, #SCI_INDICSETUNDER, #Brackets2, 1)						  
	ScintillaSendMessage(0, #SCI_INDICSETALPHA, #Brackets2, 127)					  

	For i = 0 To ArraySize(ArrBr(), 2) - 1
		ScintillaSendMessage(0, #SCI_SETINDICATORCURRENT, Toggle, #INDIC_STRAIGHTBOX) 
		ScintillaSendMessage(0, #SCI_INDICATORFILLRANGE, ArrBr(0, i), 1) 
		ScintillaSendMessage(0, #SCI_INDICATORFILLRANGE, ArrBr(1, i), 1) 
		Toggle = Bool(Not Toggle)
	Next
	
	Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 778
Joined: Fri Dec 04, 2015 9:26 pm

Re: Analyzer of brackets (?)

Post by skinkairewalker »

I recommend using goscintilla, the code is a bit old, but it still works...

https://www.purebasic.fr/english/viewto ... &start=285

https://github.com/tajmone/purebasic-ar ... oScintilla
AZJIO
Addict
Addict
Posts: 2171
Joined: Sun May 14, 2017 1:48 am

Re: Analyzer of brackets (?)

Post by AZJIO »

skinkairewalker wrote: Tue Dec 19, 2023 2:30 pm I recommend using goscintilla
You can see my Scintilla selection here. But the question was about brackets.
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Analyzer of brackets (?)

Post by ChrisR »

I don't understand the need for "If flgBracket : c + 1..." it should work without
Otherwise you fill your array from 1 to x so after, you need to read from position 1: For i = 1 To ArraySize(ArrBr(), 2)

Code: Select all

EnableExplicit

Procedure Brackets(*c.Character, Array ArrBrackets(2))
	Protected Pos = -1, Open, Close
	If *c = 0 Or *c\c = 0
		ProcedureReturn 0
	EndIf

	While *c\c
		Pos + 1
		Select *c\c
		  Case '('
		    Open + 1
		    ReDim ArrBrackets(1, Open)
		    ArrBrackets(0, Open) = Pos
		  Case ')'
		    Close + 1
		    ArrBrackets(1, Close) = Pos
		EndSelect
		*c + SizeOf(Character)
	Wend
EndProcedure

Define MyStr$, i
Define Dim ArrBr(1, 0)

MyStr$ = "word (word) (word\(f\)word) (word(f)word)"
Brackets(@MyStr$, ArrBr())

Debug "Count = " + Str(ArraySize(ArrBr(), 2))
For i = 0 To ArraySize(ArrBr(), 2) - 1
	Debug Str(ArrBr(0, i)) + " - " + Str(ArrBr(1, i))
Next

Enumeration
    #Brackets1
    #Brackets2
EndEnumeration

Define *Text
Define Toggle

If Not InitScintilla()
    End
EndIf

If OpenWindow(0, 0, 0, 630, 190, "ScintillaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	ScintillaGadget(0, 10, 10, 620, 170, 0)
	*Text = UTF8(MyStr$)
	ScintillaSendMessage(0, #SCI_SETTEXT, 0, *Text)
	FreeMemory(*Text)
	ScintillaSendMessage(0, #SCI_STYLESETSIZE, #STYLE_DEFAULT, 16) 
	
	ScintillaSendMessage(0, #SCI_INDICSETSTYLE, #Brackets1, #INDIC_STRAIGHTBOX) 
	ScintillaSendMessage(0, #SCI_INDICSETFORE, #Brackets1, $9900FF)				
	ScintillaSendMessage(0, #SCI_INDICSETUNDER, #Brackets1, 1)						  
	ScintillaSendMessage(0, #SCI_INDICSETALPHA, #Brackets1, 127)					  
	
	ScintillaSendMessage(0, #SCI_INDICSETSTYLE, #Brackets2, #INDIC_STRAIGHTBOX) 
	ScintillaSendMessage(0, #SCI_INDICSETFORE, #Brackets2, $0099FF)				
	ScintillaSendMessage(0, #SCI_INDICSETUNDER, #Brackets2, 1)						  
	ScintillaSendMessage(0, #SCI_INDICSETALPHA, #Brackets2, 127)					  

	For i = 1 To ArraySize(ArrBr(), 2)
		ScintillaSendMessage(0, #SCI_SETINDICATORCURRENT, Toggle, #INDIC_STRAIGHTBOX) 
		ScintillaSendMessage(0, #SCI_INDICATORFILLRANGE, ArrBr(0, i), 1)
		ScintillaSendMessage(0, #SCI_INDICATORFILLRANGE, ArrBr(1, i), 1)
		Toggle = Bool(Not Toggle)
	Next
	
	Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
AZJIO
Addict
Addict
Posts: 2171
Joined: Sun May 14, 2017 1:48 am

Re: Analyzer of brackets (?)

Post by AZJIO »

ChrisR
In this text:
(word\(f\)word)
The outer brackets should be red, for example, and the inner ones yellow. Brackets belonging to each other must be the same color. This is necessary so that in regular expressions, instead of highlighting all brackets, you need to highlight paired brackets in one color, and other paired brackets in a different color. Usually two colors are enough to highlight the brackets.

If the parentheses follow each other, first opening and then closing, then this is easy to do. But we have two or three opening brackets in a row, but no closing ones. Opening ones always follow each other, but closing ones can follow differently; after two open parentheses, the closing one corresponds not to the first, but to the second parenthesis. You need to do counts when the brackets begin to open several times in a row.

After the algorithm becomes clear, I need to introduce another concept as the escaped bracket "\(", which must be ignored. And if "\\(" is escaped twice, then the escape refers to the slash "\" and such a bracket is no longer is ignored, meaning I'll have to count backwards to get an odd number of "\" characters.

Notice the brackets are different colors
Image

Previously, I did the following: I found all the internal parentheses that did not have parentheses inside them and replaced them with control characters. Further in the loop, I again found the brackets at a higher level and replaced them with another control character. And this continued until there were no brackets left. Then I got the positions of the control characters. Now I wanted to do one pass by counting the parentheses if they are opened several times in order to count back the paired parentheses.
Last edited by AZJIO on Tue Dec 19, 2023 4:25 pm, edited 1 time in total.
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Analyzer of brackets (?)

Post by ChrisR »

I get it, as much for me :oops:
AZJIO
Addict
Addict
Posts: 2171
Joined: Sun May 14, 2017 1:48 am

Re: Analyzer of brackets (?)

Post by AZJIO »

Here's my old way

Code: Select all

EnableExplicit


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

Procedure RegexReplace2(RgEx, *Result.String, Replace0$, Escaped = 0)
    Protected i, CountGr, Pos, Offset = 1
    Protected Replace$
    Protected NewList item.s()
    Protected LenT, *Point
;     Static RE2
;     Static RE3
    Protected RE2
    Protected NewList ReplaceGr.ReplaceGr()

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

    If ExamineRegularExpression(RgEx, *Result\s)

        ; Поиск Esc-символов в поле замены регвыр
        If Escaped
            Replace0$ = ReplaceString(Replace0$, "\r", #CR$)
            Replace0$ = ReplaceString(Replace0$, "\n", #LF$)
            Replace0$ = ReplaceString(Replace0$, "\t", #TAB$)
            Replace0$ = ReplaceString(Replace0$, "\f", #FF$)
        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_CaseSensitive, ReplaceGr()\pos, 1)
                Else
                    Replace$ = ReplaceString(Replace$, ReplaceGr()\group, RegularExpressionMatchString(RgEx), #PB_String_CaseSensitive, 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


Procedure Brackets(*Str.String, Array ArrBrackets(1), Array ArrBrackets2(1))
	Protected Toggle = 2, tmp$, Count, Pos, i
	
	#RegExp = 0
	If CreateRegularExpression(#RegExp, "\(([^()]+?)\)",  #PB_RegularExpression_NoCase)
				Repeat
; 		For i = 1 To 9
			tmp$ = *Str\s
			RegexReplace2(#RegExp, *Str, Chr(Toggle) + "\1" + Chr(Toggle))
			If tmp$ = *Str\s
				Break
			EndIf
			tmp$ = *Str\s
			Toggle = Bool(Not (Toggle - 1)) + 1
; 			Next
					ForEver
		Else
			Debug RegularExpressionError()
		EndIf
	Count = CountString(*Str\s, Chr(2))
	ReDim ArrBrackets(Count)
	For i = 1 To Count
		Pos = FindString(*Str\s, Chr(2), Pos + 1)
		If Pos
			ArrBrackets(i) = Pos - 1
		EndIf
	Next
	
	Pos = 0
	Count = CountString(*Str\s, Chr(1))
	ReDim ArrBrackets2(Count)
	For i = 1 To Count
		Pos = FindString(*Str\s, Chr(1), Pos + 1)
		If Pos
			ArrBrackets2(i) = Pos - 1
		EndIf
	Next
; 	ReplaceString(*Str\s, Chr(2), "(", #PB_String_InPlace)
; 	ReplaceString(*Str\s, Chr(1), ")", #PB_String_InPlace)
; 			Debug *Str\s
EndProcedure

Define Txt.String
Define MyStr$, i
Define Dim ArrBr(0)
Define Dim ArrBr2(0)

Txt\s = "word (word) (word\(f\)word) (word(f)word)"
MyStr$ = Txt\s
Brackets(Txt, ArrBr(), ArrBr2())
; MyStr$ = "word (word) (word\(f\)word) (word(f)word)"
; Brackets(@MyStr$, ArrBr())

Debug "Count = " + Str(ArraySize(ArrBr()))
For i = 1 To ArraySize(ArrBr(), 2)
	Debug Str(ArrBr(i))
Next
Debug "Count = " + Str(ArraySize(ArrBr2()))
For i = 1 To ArraySize(ArrBr2(), 2)
	Debug Str(ArrBr2(i))
Next

Enumeration
    #Brackets1
    #Brackets2
EndEnumeration

Define *Text
Define Toggle

If Not InitScintilla()
    End
EndIf

If OpenWindow(0, 0, 0, 630, 190, "ScintillaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	ScintillaGadget(0, 10, 10, 620, 170, 0)
	*Text = UTF8(MyStr$)
	ScintillaSendMessage(0, #SCI_SETTEXT, 0, *Text)
	FreeMemory(*Text)
	ScintillaSendMessage(0, #SCI_STYLESETSIZE, #STYLE_DEFAULT, 16) 
	
	ScintillaSendMessage(0, #SCI_INDICSETSTYLE, #Brackets1, #INDIC_STRAIGHTBOX) 
	ScintillaSendMessage(0, #SCI_INDICSETFORE, #Brackets1, $9900FF)				
	ScintillaSendMessage(0, #SCI_INDICSETUNDER, #Brackets1, 1)						  
	ScintillaSendMessage(0, #SCI_INDICSETALPHA, #Brackets1, 127)					  
	
	ScintillaSendMessage(0, #SCI_INDICSETSTYLE, #Brackets2, #INDIC_STRAIGHTBOX) 
	ScintillaSendMessage(0, #SCI_INDICSETFORE, #Brackets2, $0099FF)				
	ScintillaSendMessage(0, #SCI_INDICSETUNDER, #Brackets2, 1)						  
	ScintillaSendMessage(0, #SCI_INDICSETALPHA, #Brackets2, 127)					  

	For i = 1 To ArraySize(ArrBr())
		ScintillaSendMessage(0, #SCI_SETINDICATORCURRENT, Toggle, #INDIC_STRAIGHTBOX) 
		ScintillaSendMessage(0, #SCI_INDICATORFILLRANGE, ArrBr(i), 1) 
	Next
	Toggle = Bool(Not Toggle)
	For i = 1 To ArraySize(ArrBr2())
		ScintillaSendMessage(0, #SCI_SETINDICATORCURRENT, Toggle, #INDIC_STRAIGHTBOX) 
		ScintillaSendMessage(0, #SCI_INDICATORFILLRANGE, ArrBr2(i), 1) 
	Next
	
	Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Analyzer of brackets (?)

Post by ChrisR »

Maybe something like this, with a Stack list

Code: Select all

EnableExplicit

Procedure Brackets(*c.Character, Array ArrBrackets(2))
  Protected Pos = -1, Open
  Protected NewList Stack()
	If *c = 0 Or *c\c = 0
		ProcedureReturn 0
	EndIf

	While *c\c
	  Pos + 1
	  Select *c\c
	    Case '('
	      Open + 1
	      AddElement(Stack())
	      Stack() = Open
	      ReDim ArrBrackets(1, Open)
	      ArrBrackets(0, Open) = Pos
	    Case ')'
	      If Not ListSize(Stack())
	        Debug "Opening brackets are missing"
	      Else
	        ;LastElement(Stack())
	        ArrBrackets(1, Stack()) = Pos
	        DeleteElement(Stack())
	      EndIf
	  EndSelect
	  *c + SizeOf(Character)
	Wend
	
	If ListSize(Stack())
	  Debug "Closing brackets are missing"
	EndIf 
EndProcedure

Define MyStr$, i
Define Dim ArrBr(1, 0)

MyStr$ = "word (word) (word\(f\)word) (word(f)word)"
;MyStr$ = "(W(W))(W(W)(W))"
Brackets(@MyStr$, ArrBr())

Debug "Count = " + Str(ArraySize(ArrBr(), 2))
For i = 1 To ArraySize(ArrBr(), 2)
	Debug Str(ArrBr(0, i)) + " - " + Str(ArrBr(1, i))
Next

Enumeration
    #Brackets1
    #Brackets2
EndEnumeration

Define *Text
Define Toggle

If Not InitScintilla()
    End
EndIf

If OpenWindow(0, 0, 0, 630, 190, "ScintillaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	ScintillaGadget(0, 10, 10, 620, 170, 0)
	*Text = UTF8(MyStr$)
	ScintillaSendMessage(0, #SCI_SETTEXT, 0, *Text)
	FreeMemory(*Text)
	ScintillaSendMessage(0, #SCI_STYLESETSIZE, #STYLE_DEFAULT, 16) 
	
	ScintillaSendMessage(0, #SCI_INDICSETSTYLE, #Brackets1, #INDIC_STRAIGHTBOX) 
	ScintillaSendMessage(0, #SCI_INDICSETFORE, #Brackets1, $9900FF)				
	ScintillaSendMessage(0, #SCI_INDICSETUNDER, #Brackets1, 1)						  
	ScintillaSendMessage(0, #SCI_INDICSETALPHA, #Brackets1, 127)					  
	
	ScintillaSendMessage(0, #SCI_INDICSETSTYLE, #Brackets2, #INDIC_STRAIGHTBOX) 
	ScintillaSendMessage(0, #SCI_INDICSETFORE, #Brackets2, $0099FF)				
	ScintillaSendMessage(0, #SCI_INDICSETUNDER, #Brackets2, 1)						  
	ScintillaSendMessage(0, #SCI_INDICSETALPHA, #Brackets2, 127)					  

	For i = 1 To ArraySize(ArrBr(), 2)
		ScintillaSendMessage(0, #SCI_SETINDICATORCURRENT, Toggle, #INDIC_STRAIGHTBOX) 
		ScintillaSendMessage(0, #SCI_INDICATORFILLRANGE, ArrBr(0, i), 1)
		ScintillaSendMessage(0, #SCI_INDICATORFILLRANGE, ArrBr(1, i), 1)
		Toggle = Bool(Not Toggle)
	Next
	
	Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
Edit: Add "Opening brackets are missing"
juergenkulow
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 25, 2019 10:18 am

Re: Analyzer of brackets (?)

Post by juergenkulow »

Code: Select all

MyStr$ = "</?\w+((\s+\w+(\s*=\s*(?:"+#DQUOTE$+".*?"+#DQUOTE$+"|'.*?'|[^'"+#DQUOTE$+">\s]+))?)+\s*|\s*)/?>"
I have questions to your sample:
Are <[]> also brackets?
Must ( follow by ), < by > and [ by ] ?
Is "(<[]>)" a string?
Is '(' not a bracket?
What ist '" ?
Is синус(π ) allowed?
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Analyzer of brackets (?)

Post by ChrisR »

@AZJIO
It doesn't suit you, with the LIFO stack list example ? I don't see any other way.

If you have other brackets [], you can do it the same way, with a structured list.
And check that the type (Square or SquareBracket) of a closing bracket always matches the type of the last opening bracket, to avoid having (Word[f)] or [Word(f]).
AZJIO
Addict
Addict
Posts: 2171
Joined: Sun May 14, 2017 1:48 am

Re: Analyzer of brackets (?)

Post by AZJIO »

ChrisR
Yes, it's an interesting solution.
juergenkulow
[] - these brackets cannot be nested and are highlighted as regular characters of the same color.
<> - These are not part of a regular expression. These are html elements.
Post Reply