Jump to content

Elegant idea to catch a function params


mary
 Share

Recommended Posts

Hi !

imagine that you parse a javascript code and you want to catch all arguments of a given function. my first idea is to

use StringSplit ( $fucntion_definition_line, ",") But the problem is that in some function, parameters may contain a comma "," caracter.

here is an exemple of javascript function:

my_JS_function(12,0,false, ' my text contain a comma , !!', true,0)

Please if you have an idea to catch all arguments of any javascript function ?

thinks a lot

Link to comment
Share on other sites

my_JS_function(12,0,false, ' my text contain a comma , !!', true,0)

The Regular Expressions feature of AutoIt is currently very volitile and subject to extensive change. that is why it isn't in the official documentation. You can wrap the regex capabilities of another language in a COM object (or parallel-running exe) if you like.

Try using this regular expression. The information you want is in the param groupof which there may be any number of matches per arglist capture.

.Net or Basic:
(?<funcname>[^\(]+)(?<arglist>\((?<paramitem>(?<param>'[^']*'|[^,\)]+)(?<delim>, ?)?)*\))

java script:
/(?<funcname>[^\(]+)(?<arglist>\((?<paramitem>(?<param>'[^']*'|[^,\)]+)(?<delim>, ?)?)*\))/

Perl (string), C or :
"(?<funcname>[^\\(]+)(?<arglist>\\((?<paramitem>(?<param>'[^']*'|[^,\\)]+)(?<delim>, ?)?)*\\))" 

Perl (m// operator):
m/(?<funcname>[^\(]+)(?<arglist>\((?<paramitem>(?<param>'[^']*'|[^,\)]+)(?<delim>, ?)?)*\))/

Python:
r"(?<funcname>[^\(]+)(?<arglist>\((?<paramitem>(?<param>'[^']*'|[^,\)]+)(?<delim>, ?)?)*\))"

DEBUG:

my_JS_function
my_JS_function
my_JS_function(
my_JS_function(backtrack
my_JS_function(12
my_JS_function(12
my_JS_function(12,
my_JS_function(12,
my_JS_function(12,backtrack
my_JS_function(12,0
my_JS_function(12,0
my_JS_function(12,0,
my_JS_function(12,0,
my_JS_function(12,0,backtrack
my_JS_function(12,0,false
my_JS_function(12,0,false
my_JS_function(12,0,false,
my_JS_function(12,0,false, 
my_JS_function(12,0,false, 
my_JS_function(12,0,false, '
my_JS_function(12,0,false, ' my text contain a comma , !!
my_JS_function(12,0,false, ' my text contain a comma , !!'
my_JS_function(12,0,false, ' my text contain a comma , !!'
my_JS_function(12,0,false, ' my text contain a comma , !!',
my_JS_function(12,0,false, ' my text contain a comma , !!', 
my_JS_function(12,0,false, ' my text contain a comma , !!', 
my_JS_function(12,0,false, ' my text contain a comma , !!', backtrack
my_JS_function(12,0,false, ' my text contain a comma , !!', true
my_JS_function(12,0,false, ' my text contain a comma , !!', true
my_JS_function(12,0,false, ' my text contain a comma , !!', true,
my_JS_function(12,0,false, ' my text contain a comma , !!', true,
my_JS_function(12,0,false, ' my text contain a comma , !!', true,backtrack
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0backtrack
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0backtrack
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0backtrack
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0backtrack
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0)
my_JS_function(12,0,false, ' my text contain a comma , !!', true,0)
Match found

I love regular expressions :)

Link to comment
Share on other sites

thinks sohfeyr for you help !

also i love regexp but , as you said, it have problem in autoit...,

using regexp from other external tools (exe or com object) is a solution but it decrease speed of code ! specially when speed is important for the goal of project.

any way i'll tray Javascript library/com but dont know how to call javascript code from autoit...

Link to comment
Share on other sites

using regexp from other external tools (exe or com object) is a solution but it decrease speed of code ! specially when speed is important for the goal of project.

any way i'll tray Javascript library/com but dont know how to call javascript code from autoit...

I've never heard of a way to call Javascript code from AutoIt either. You might be able to run an HTA file, but not with normal security measures in place.

Look here for a way to call Perl functions from AutoIt. That *should* include Perl's support for regular expressions, and you are far more likely to find up-to-date documentation for Perl RegExp... Other people have had great successes with wrapping functions in FreeBasic. (See "Callback helper dll" in my signature.)

I realize this isn't exactly what you were wanting, but I wouldn't want to give you a bum steer into code that uses a function under renovation. AutoIt syntax and maybe even support for RegExp is up in the air. I suppose you could use those functions as-is, but what happens when another beta comes along with a function you need? Your RegExp support is suddenly full of bugs. It is a serious maintainability problem! (See all the people who got bugs in their code when DLLStructDelete was removed? Think that but without a simple fix.) That's why I ended up wrapping the .Net RegEx, Group and Match objects and exposed them inside another process that would be running anyways.

If you just want simple parsing, try this (very rough, untested, and honestly I'm not convinced that it would go any faster than signalling another program that is already running):

Func ImmunizeQuotedCommas(ByRef $str, $offset=-1)
   $firstquote = StringIndexOf($str, "'", $offset+1)
   $secondquote = StringIndexOf($str, "'", $firstquote+1)
   $commaIdx = StringIndexOf($str, ",", $firstquote+1)
   If $commaIdx < $secondquote then
      $str=StringReplace($str, $commaIdx, "") ;  = Alt-0131, Windows: Western; Alt-0192, Unicode
      ImmunizeQuotedCommas($str, $secondQuote)
   ElseIf $commaIdx > $secondquote then
      ImmunizeQuotedCommas($str, $commaIdx)
   ElseIf $commaIdx = 0 then ; No more parameters, and no commas in current string
      Return
   EndIf
   Return
EndFunc

Func StringIndexOf($str, $char, $startidx)
   For $i = $startidx to StringLen($str)-$startIdx
      If StringMid($str, $i) = $char then
         Return $i
      EndIF
   Next
   Return 0
EndFunc

You can then use StringSplit freely, as long as you replace any occurrances of (or whatever symbol) with commas in the individual strings.

This only supports one comma per quoted string (I wouldn't want to have to take all the fun out of this for you :) ) but you can easily break that conditional into parts and put the first part in a While loop with the $commaIdx = line. I still think regular expressions are the better solution, even if implementing them right now in any maintainable form adds a module to your overall software architecture. But that's just me. I'm sure a lot of people will disagree and favor the simpler (more elementary) approach of manual parsing.

I wrote a program using the more elementary technique, and it is such a maintenance nightmare I'm writing version 2.0 of it in my spare time as a matter of both pride and necessity. If you foresee doing a lot of parsing, I strongly encourage you to hitch your wagon to a wrapped RegExp engine that is already established.

Edit: StringInStr doesn't have a startindex parameter!

Edited by sohfeyr
Link to comment
Share on other sites

  • Moderators

Edit:

OOps... Not working BRB :)

Edit2:

Messy, but should work -

#include <array.au3>

$s = "MsgBox)"
$a = _GetParams($s)
If @error = 1 Then MsgBox(64, 'Info', 'Not a function')

$s = "MsgBox()"
$a = _GetParams($s)
If @error = 2 Then MsgBox(64, 'Info', 'No Parameter')

$s = "MsgBox(0, 0, 0)"
$a = _GetParams($s)
_ArrayDisplay($a, '')

$s = "MsgBox(0, 'Title', 'Text, write something here')"
$a = _GetParams($s)
_ArrayDisplay($a, '')

Func _GetParams($sString)
    Local $aSplit = StringSplit($sString, '('), $aReturn[2], $iAdd
    If $aSplit[0] < 2 Then Return SetError(1, 0, 0)
    $aSplit = StringSplit($aSplit[2], ')')
    $sString = $aSplit[1]
    If $sString = '' Then Return SetError(2, 0, 0) ; No params
    If Not StringInStr($sString, ',') Then 
        $aReturn[1] = $sString
        Return $aReturn
    EndIf
    $aSParm = _ReturnStringParams($sString)
    If IsArray($aSParm) Then
        For $iCC = 1 To $aSParm[0]
            $sString = StringReplace($sString, $aSParm[$iCC], '')
        Next
        $aSplit = StringSplit($sString, ',')
        ReDim $aReturn[$aSplit[0] + 1]
        For $iCC = 1 To $aSplit[0]
            If StringLen(StringStripWS($aSplit[$iCC], 8)) = 0 Then
                $iAdd += 1
                $aReturn[$iCC] = $aSParm[$iAdd]
            Else
                $aReturn[$iCC] = $aSplit[$iCC]
            EndIf
        Next
        Return $aReturn
    EndIf
    Return StringSplit($sString, ',')
EndFunc

Func _ReturnStringParams($sString)
    Local $sTemp, $sSQ, $sDQ, $vDelim, $sHold, $sDiff
    $sTemp = $sString
    $sTemp = StringReplace($sTemp, '""', '~~')
    $sTemp = StringReplace($sTemp, "''", '@@')
    While StringLen($sTemp) > 0
        $sSQ = StringInStr($sTemp, "'")
        $sDQ = StringInStr($sTemp, '"')
        If Not $sSQ And Not $sDQ Then ExitLoop
        If $sDQ > 0 And ($sSQ > $sDQ Or $sSQ = 0) Then
            $vDelim = '"'
            $sTemp = StringTrimLeft($sTemp, $sDQ)
            $sString = StringTrimLeft($sString, $sDQ)
        Else
            $vDelim = "'"
            $sTemp = StringTrimLeft($sTemp, $sSQ)
            $sString = StringTrimLeft($sString, $sSQ)
        EndIf
        $sDiff = StringInStr($sTemp, $vDelim, 2)
        If $sDiff Then
            $sHold &= $vDelim & StringLeft($sString, $sDiff - 1) & $vDelim & Chr(01)
            $sTemp = StringTrimLeft($sTemp, $sDiff)
            $sString = StringTrimLeft($sString, $sDiff)
        EndIf
    WEnd
    If $sHold Then Return StringSplit(StringTrimRight($sHold, 1), Chr(01))
    Return SetError(1, 0, 0)
EndFunc
Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

  • Moderators

thinks a lot for your help !

finally, i'll use external regexp engine (vbs or perlxx.dll).

Typical .... However this works just fine:
#include <array.au3>

$s = "my_JS_function(12,0,false, ' my text contain a comma , !!', true,0))"
$a = _GetParams($s)
_ArrayDisplay($a, '')

$s = "adofijweolj afjalsdjfoawerlamsf oas falskjdfoas fl a my_JS_function(12,0,false, ' my text contain a comma , !!', true,0) adofijaldsfjowejla knfoajsd"
$a = _GetParams($s, "my_JS_function")
_ArrayDisplay($a, '')

Func _GetParams($sString, $sFuncName = '')
    If $sFuncName <> '' Then
        $sString = StringTrimLeft($sString, StringInStr($sString, $sFuncName) - 1)
    EndIf
    Local $aSplit = StringSplit($sString, '('), $aReturn[2], $iAdd
    If $aSplit[0] < 2 Then Return SetError(1, 0, 0)
    $aSplit = StringSplit($aSplit[2], ')')
    $sString = $aSplit[1]
    If $sString = '' Then Return SetError(2, 0, 0) ; No params
    If Not StringInStr($sString, ',') Then 
        $aReturn[1] = $sString
        Return $aReturn
    EndIf
    $aSParm = _ReturnStringParams($sString)
    If IsArray($aSParm) Then
        For $iCC = 1 To $aSParm[0]
            $sString = StringReplace($sString, $aSParm[$iCC], '')
        Next
        $aSplit = StringSplit($sString, ',')
        ReDim $aReturn[$aSplit[0] + 1]
        For $iCC = 1 To $aSplit[0]
            If StringLen(StringStripWS($aSplit[$iCC], 8)) = 0 Then
                $iAdd += 1
                $aReturn[$iCC] = $aSParm[$iAdd]
            Else
                $aReturn[$iCC] = $aSplit[$iCC]
            EndIf
        Next
        Return $aReturn
    EndIf
    Return StringSplit($sString, ',')
EndFunc

Func _ReturnStringParams($sString)
    Local $sTemp, $sSQ, $sDQ, $vDelim, $sHold, $sDiff
    $sTemp = $sString
    $sTemp = StringReplace($sTemp, '""', '~~')
    $sTemp = StringReplace($sTemp, "''", '@@')
    While StringLen($sTemp) > 0
        $sSQ = StringInStr($sTemp, "'")
        $sDQ = StringInStr($sTemp, '"')
        If Not $sSQ And Not $sDQ Then ExitLoop
        If $sDQ > 0 And ($sSQ > $sDQ Or $sSQ = 0) Then
            $vDelim = '"'
            $sTemp = StringTrimLeft($sTemp, $sDQ)
            $sString = StringTrimLeft($sString, $sDQ)
        Else
            $vDelim = "'"
            $sTemp = StringTrimLeft($sTemp, $sSQ)
            $sString = StringTrimLeft($sString, $sSQ)
        EndIf
        $sDiff = StringInStr($sTemp, $vDelim, 2)
        If $sDiff Then
            $sHold &= $vDelim & StringLeft($sString, $sDiff - 1) & $vDelim & Chr(01)
            $sTemp = StringTrimLeft($sTemp, $sDiff)
            $sString = StringTrimLeft($sString, $sDiff)
        EndIf
    WEnd
    If $sHold Then Return StringSplit(StringTrimRight($sHold, 1), Chr(01))
    Return SetError(1, 0, 0)
EndFunc
Run it, It will even dig through it similar to RegExp ... Or try to use the StringRegExp() internally.... I only did this because of the comment of wanting to stay native. And as about as fast as you are going to get calling outside apps to do the work.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

SmOke_N, you code works ! thinks for your help.

MHz, thinks for your StringRegExpVB.au3 (we are waiting for a StringRegExpJS.au3 :) )

Hope a mature RegExp implementation for autoit !

Edited by mary
Link to comment
Share on other sites

MHz, thinks for your StringRegExpVB.au3 (we are waiting for a StringRegExpJS.au3 :P )

Hope a mature RegExp implementation for autoit !

$vbs.language = "vbscript"

and modify the regex code to jscript. The regex syntax for regex can be found in script56.chm. :)

Edited by MHz
Link to comment
Share on other sites

Finally i found an elegant an very rapid solution (maybe more speed than regexp, specially when there is a lot of arguments.

#include <Array.au3>
$texte="1,2,'this is an text argument containing a comma , and an other comma , no problem !! ',4,'othertexte'" ; juste a list of arguments



Func ready_for_split($t) ; $t is a the list of arguments (the hole string beween parentheses)
$t=StringSplit($t,"")

Local $istxt=0
$r=""
For $i=1 to $t[0]
    
    IF $t[$i]="'" Then
    $istxt= not $istxt
    EndIf
       
       IF $t[$i]="," And $istxt then
       
        $t[$i]="ß" ; this is an exotic caracter that we can replace it with the comma after split

        EndIf
$r=$r & $t[$i]

Next

Return $r

EndFunc

$tab=StringSplit(ready_for_split($texte),",")
_ArrayDisplay($tab,"splited and ready to replace 'ß' with ',' ;)")
Edited by mary
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...