Find matching brackets (or other nested tag pairs)

Share your advanced PureBasic knowledge/code with the community.
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Find matching brackets (or other nested tag pairs)

Post by Lunasole »

Hi once more. Here is some stuff which can parse nested brackets or other tags.
Tag len currently is limited to 1 char, but can be easily modified to fit any len.
Also it's not too optimized, I've just made it 30 min ago for "let it do what needed" ^^
But should be fine enough anyway. Additionaly, some error-correction added for cases when opening or closing tag is missing.

Code: Select all

EnableExplicit


; v 1.0.0.1
;	2016			(c) Luna Sole

; returns array with string data between matching pair of 2 specified chars
; StrIn$		a string to parse
; Char1$		character which opens pair
; Char2$		closing character
; UseWildcards	if true, then wildcards like "Char1$ + % + INDEX + % + Char2$" are used instead of nested pairs
; RETURN:		number of pairs found and data placed to Out$() array starting from index 1
Procedure GetPairs (Array Out$(1), StrIn$, Char1$ = "[", Char2$ = "]", UseWildcards = #False)
	Protected CntMin, LenMax = Len(StrIn$)
	Protected Dim Chars1.POINT(LenMax), Cnt1, Tmp1 ; the X field used to mark Char1 positions
	Protected Dim Chars2.POINT(LenMax), Cnt2, Tmp2 ; Y - to mark Char2
	Protected Tmp, tChr$ = " "
	Protected OutCount

	; step 1, mark all matches
	For Tmp = 1 To LenMax
		PokeC(@tChr$, PeekC(@StrIn$ + (Tmp - 1) * SizeOf(Character))) ; tChr$ = Mid(StrIn$, Tmp, 1)
		If tChr$ = Char1$ 
			Cnt1 + 1	; opening char found
			Chars1(Cnt1)\x = Tmp
		ElseIf tChr$ = Char2$ 
			Cnt2 + 1	; closing char
			Chars2(Cnt2)\y = Tmp
		EndIf
	Next Tmp
	
	; step 2, fix mismatches + prepare output buffer
	If Cnt1 > Cnt2
		Cnt2 + 1
		CntMin = 1
		Chars2(Cnt2)\y = LenMax
		Dim Out$(Cnt1)
	ElseIf Cnt2 > Cnt1
		Chars1(0)\x = 1
		CntMin = 0
		Dim Out$(Cnt2)
	Else
		CntMin = 1
		Dim Out$(Cnt1)
	EndIf

	; step 3, collect results
	For Tmp1 = Cnt1 To CntMin Step -1
		For Tmp2 = 1 To Cnt2
			If Chars2(Tmp2)\y > Chars1(Tmp1)\x
				Chars1(Tmp1)\y = Chars2(Tmp2)\y
				OutCount + 1
				If UseWildcards And OutCount > 1
					If Chars1(Tmp1 + 1)\x >= Chars1(Tmp1)\x And Chars1(Tmp1 + 1)\y <= Chars1(Tmp1)\y
						; add result with wildcard
						Out$(OutCount) = Mid(StrIn$, Chars1(Tmp1)\x, Chars1(Tmp1 + 1)\x - Chars1(Tmp1)\x) + 
						                 Char1$ + "%" + Str(OutCount - 1) + "%" + Char2$ + 
						                 Mid(StrIn$, Chars1(Tmp1 + 1)\y + 1, Chars1(Tmp1)\y - Chars1(Tmp1 + 1)\y)  
					Else
						Out$(OutCount) = Mid(StrIn$, Chars1(Tmp1)\x, 1 + Chars1(Tmp1)\y - Chars1(Tmp1)\x)
					EndIf
				Else
					; add raw result
					Out$(OutCount) = Mid(StrIn$, Chars1(Tmp1)\x, 1 + Chars1(Tmp1)\y - Chars1(Tmp1)\x)
				EndIf
				
				Chars2(Tmp2)\y = -1
				Break
			EndIf
		Next Tmp2
	Next Tmp1
	
	; fin
	ProcedureReturn OutCount
EndProcedure


;;;;;;;;;
; usage ;
Global Dim T$(0)
Global Tmp


Debug Str(GetPairs(T$(), "[0][1][2][5[6]]", "[", "]", 1)) + " found:" ; that doesn't work OK in previous version
For Tmp = 1 To ArraySize(T$())
	Debug T$(Tmp)
Next Tmp
Debug ""

Debug Str(GetPairs(T$(), "[000[11[2[33]2]11]000]", "[", "]", 1)) + " found:"
For Tmp = 1 To ArraySize(T$())
	Debug T$(Tmp)
Next Tmp
Debug ""

; here should be example using recursive wildcards expanding, but looks like I'm too lazy to finish it today ^^
; Out$(Count) = ReplaceString(Out$(Count), Char1$ + "%" + Str(Count - 1) + "%" + Char2$, Out$(Count-1))
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Find matching brackets (or other nested tag pairs)

Post by Lunasole »

Updated because of bug fixes / improvements
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Find matching brackets (or other nested tag pairs)

Post by Kwai chang caine »

I don't know, what is the real use of this code, but it works very well
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Find matching brackets (or other nested tag pairs)

Post by Lunasole »

Kwai chang caine wrote:I don't know, what is the real use of this code
Nice question, btw, as I don't know it too ^^

Well, years ago I've used it to parse some server configs of Lineage II server. The current version posted here is extended and improved version of that old code (originally it was "just another custom algorithm used for single specific case").
So I did newer version of it "for fun"... or just because I've remembered it being smoked out. Not sure and doesn't matter :3 Probably there will be a case to use this.
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Find matching brackets (or other nested tag pairs)

Post by Kwai chang caine »

Nice question, btw, as I don't know it too ^^
:lol:
Personally, it's not the first time i create a code i don't understand, even nearly all the days :mrgreen: :oops:
But never i create a code, i don't know why ? :lol:

Thanks also for your explanation :wink: 8)
ImageThe happiness is a road...
Not a destination
Post Reply