Jump to content


Photo

Get elements from a Json string (BracketParser)


  • Please log in to reply
6 replies to this topic

#1 Flowerpiggy

Flowerpiggy
  • Members
  • 45 posts

Posted 29 May 2011 - 04:15 PM

Hi

Here is a simple function that get bracketed elements within another bracket.

For example, if the string is "[XXX[1]XXX[2]X[3]XXX]", the function will acquire [1], [2] and [3] and put them into an array.

You can specify a depth of level. Thus if you have a string like [XXX[1[third level1]]XXX[2]X[3[third level2]XXX]. The function can extract [thirdlevel1] and [thirdlevel2] if you specify level depth to 3.

A question: can I write a function which outputs objects (arrays)? I found it rather lame to use a separator symbol.

Thank you!


InputText := "[XXX[1]XXX[2]X[3]XXX]"
OutputArray :=object()
BracketParse(InputText,OutputString)

msgbox % OutputString

stringsplit , TempArray, OutputString,``
loop , %TempArray0%
{
    msgbox % TempArray%a_index%
}



BracketParse(InputText, byref OutputString, SearchLevel=2)
{
    LeftBrackets := "{[("
    RightBrackets := ")]}"
    ElementCounter := 0
    Counter :=strlen(InputText)
    loop, %Counter%
    {
        CurrentChar := SubStr(InputText, A_Index, 1)
        If (InStr(LeftBrackets, CurrentChar))
            CurrentLevel += 1
        If (CurrentLevel >= SearchLevel)
            CurrentElement .= CurrentChar
        
         If (InStr(RightBrackets, CurrentChar))
        {
            CurrentLevel := CurrentLevel - 1
            If (CurrentLevel = SearchLevel - 1)
            {  
                OutputString .= CurrentElement . "``"
                CurrentElement =
            }
        }    
    }  
    len := strlen(OutputString) -1
stringleft, OutputString, OutputString, %len%    
}


#2 Flowerpiggy

Flowerpiggy
  • Members
  • 45 posts

Posted 29 May 2011 - 05:06 PM

Here is a way to pass an array out of a function:-) I am happy now.

TempArray := object()
InputText := "[XXX[1]XXX[2]X[3]XXX]"

BracketParse(InputText, "TempArray") ;array name is passed to the function as a string

msgbox % TempArray.maxindex()

for index, element in TempArray 
{

    MsgBox % "Element number " . index . " is " . element
    
}

BracketParse(InputText, ArrayName, SearchLevel=2)
{
    LeftBrackets := "{[("
    RightBrackets := ")]}"
    ElementCounter := 0        
    Counter :=strlen(InputText)
    loop, %Counter%
    {
        CurrentChar := SubStr(InputText, A_Index, 1)
        If (InStr(LeftBrackets, CurrentChar))
            CurrentLevel += 1
        If (CurrentLevel >= SearchLevel)
            CurrentElement .= CurrentChar
        
         If (InStr(RightBrackets, CurrentChar))
        {
            CurrentLevel := CurrentLevel - 1
            If (CurrentLevel = SearchLevel - 1)
            {  
                %ArrayName%.insert(CurrentElement)                
                ;OutputString .= CurrentElement . "``"
                CurrentElement =
            }
        }    
    }      
}


#3 fincs

fincs
  • Fellows
  • 1532 posts

Posted 29 May 2011 - 06:36 PM

BracketParse(InputText, "TempArray") ;array name is passed to the function as a string

You don't seem to have understood what arrays really are in AHK_L. Please take some time to read the documentation (especially the introductory section before the table of contents).

HTH

#4 Flowerpiggy

Flowerpiggy
  • Members
  • 45 posts

Posted 30 May 2011 - 07:20 AM

I know what autohotkey_L array is and I use it a lot, maybe not as much as you:-)

Anyway, my code works. With Autohotkey, variable values can be easily used as another variable name. I think it's brilliant and there is no reason not to use it.

I know how to pass an array into a function (ads a * to the variable) but I don't know how to pass an array out of it other than my method.

To prove my point, the following function StrSplit splits a string and put the substrings into a real Autohotkey_L array as opposed to a pseudo array StringSplit does.


Colors = red,green,blue

ColorArray := object()
StrSplit(Colors, ",", "ColorArray")

msgbox % ColorArray.1



Strsplit(InputStr, Separator, ArrayName)
{
	StringSplit, TempArray, InputStr, %Separator%
	Loop, %TempArray0%
	{
    %ArrayName%.insert(TempArray%a_index%)    
	}
}


#5 fincs

fincs
  • Fellows
  • 1532 posts

Posted 30 May 2011 - 09:43 AM

But why are you passing a variable name? You can pass objects to functions AND return them. Note that your code will NOT work if the variable is local to a function.

For example, this will work:
arr := ["red", "green", "blue"]
SomeFunc(arr)
MsgBox % arr.1 ; displays 'dinner'
MsgBox % OtherFunc().1 ; also displays 'dinner'

SomeFunc(a)
{
    a.1 := "dinner"
}

OtherFunc()
{
    return ["dinner", "death"]
}

So, use this instead:
Colors = red,green,blue

ColorArray := StrSplit(Colors, ",")

msgbox % ColorArray.1

Strsplit(InputStr, Separator)
{
   Array := []
   StringSplit, TempArray, InputStr, %Separator%
   Loop, %TempArray0%
   {
    Array.insert(TempArray%a_index%)    
   }
   return Array
}

Even better (no ugly dynamic var references):
arr := StrSplit("red,green,blue", ",")
MsgBox % arr.1

StrSplit(InputStr, Delimiter="")
{
    arr := []
    Loop, Parse, InputStr, % Delimiter
        arr._Insert(A_LoopField)
    return arr
}

HTH

#6 Flowerpiggy

Flowerpiggy
  • Members
  • 45 posts

Posted 30 May 2011 - 11:23 AM

Thank you Fincs. These functions look GREAT! I learnt a lot.


Note that your code will NOT work if the variable is local to a function.


You may be wrong with this. The variable is local and it still works. The reason is that you just pass a name of the object that is already created before calling as a string and the function adds elements to that object. Please notice I don't use "global" command in my function.

#7 fincs

fincs
  • Fellows
  • 1532 posts

Posted 30 May 2011 - 11:44 AM

It's the infamous "Common Source of Confusion" once again (yeah, that's the "official" name). Dynamic dereferences inside functions that resolve to a non-existant local variable are redirected to the global scope instead:

var = value
Func()
MsgBox %var% ; displays 'dinner'

Func()
{
    name = var
    %name% = dinner ; a local variable called 'var' doesn't exist, so it is searched for in the global scope
}

Common source of confusion: Any non-dynamic reference to a variable creates that variable the moment the script launches. For example, when used outside a function, MsgBox %Array1% creates Array1 as a global the moment the script launches. Conversely, when used inside a function MsgBox %Array1% creates Array1 as one of the function's locals the moment the script launches (unless assume-global is in effect), even if Array and Array0 are declared global.