Jump to content

Matching text in strings


daishi5
 Share

Recommended Posts

I have a scheduled task that was deployed using AT, and I have a script that I want to use to check that the scheduled task is installed on the correct domain machines. My only problem is, I have no experience working with strings. The output from AT is always formatted the same, so I just need to match a text string of c:\reboot.exe and if that is present in the string, I want to capture the number at the start of the line.

Status ID   Day                     Time          Command Line
-------------------------------------------------------------------------------
        1   Each W                  5:30 AM       c:\reboot.exe
        2   Each W                  5:30 AM       c:\reboot.exe

So, for this, I would want to output 1 and 2 to variables or an array (I assume I want an array) so that I can then feed them back into more commands.

This is what I have so far for grabbing the AT output. It is very basic, and I split it into several strings of 1 line each, because I think it reduces my chance of grabbing the wrong ID number.

#include <Constants.au3>
AutoItSetOption("MustDeclareVars", 1)

dim $foo
dim $line
dim $count
dim $test

;retrieve the scheduled tasks from the target machine
$foo = Run('at \\lteis007', "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
Processwaitclose($foo)
$line = string(StdoutRead($foo))
;check the output from the AT command
msgbox(1,"test",$line)
;split the output into seperate lines, and then double check the number of lines after the split
$test = stringsplit($line,@LF)
msgbox(1,"testcount",$test[0])
;display each line one by one, just one more check
$count=0
while $count<$test[0]
    $count=$count+1
    msgbox(1,"test lines",$test[$count])
WEnd

Exit

If it is necessary, I can also post the full script code, if there is a better way to go about scanning a batch of computers in the domain.

Link to comment
Share on other sites

StringRegExp(). Give it a shot. If you have trouble with the RegExp pattern (it's own learning curve), post back here for help from (the many) RegExp geeks around here!

;)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

StringRegExp(). Give it a shot. If you have trouble with the RegExp pattern (it's own learning curve), post back here for help from (the many) RegExp geeks around here!

;)

That will help, I had really hit a wall because I have never worked with strings and did not even know how to start looking at this. I will read the help file and see if I can get what I need.

Link to comment
Share on other sites

That will help, I had really hit a wall because I have never worked with strings and did not even know how to start looking at this. I will read the help file and see if I can get what I need.

If you get stuck, post what you tried for more help. There's nothing RegExp Geeks like better than training up a new RegExp Geek!

;)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

If you get stuck, post what you tried for more help. There's nothing RegExp Geeks like better than training up a new RegExp Geek!

;)

Didn't take me long.

Matching string looks like this:

Status ID   Day                     Time          Command Line
-------------------------------------------------------------------------------
        1   Each W                  5:30 AM       c:\reboot.exe
        2   Each W                  5:30 AM       c:\reboot.exe

The expression is

$task=stringregexp($line, '([0-9]{1,2})(?i:   Each [A-Z]{1,2}                  [0-9]:[0-9]{1,2} [A-Z]{1,2}       c:\\reboot.exe)', 1)

After this, I do a series of message boxes, $task[0] returns 1 like I expect, but $task[1] gives me an "Array variable has incorrect number of subscripts or subscript dimension range exceeded" error. I tried the regular expression tester that I found in the help file, the test string works in there, but I assume I broke something in my array.

Now for my new questions:

Not sure what I am doing wrong, when I did this using stringsplit I did not have to declare the size of the array, should I be doing that here?

Is there a way to output the number of matches stored in the array, or do I have to go through the array till I stop finding information stored in them when I use the output?

Is there an easier way to ignore all the text between the first number and "c:\reboot.exe" I managed to make it work, but I bet I am missing a much easier method.

Edit: Ok, I think I may have found why I am getting only the 1 back. Reading the help file, it seems that I am probably getting the "1" as an error rather than an actual match. This is a problem, because I actually expect to receive "1" back fairly often, so I need to figure out how to tell the difference between a "1" as an error and a "1" as a valid result. So, I will do some more help file digging.

Edited by daishi5
Link to comment
Share on other sites

If you get an error, there won't be an array returned (good idea to test @error and/or IsArray()). And test with Ubound() before you assume a certain number of elements in any returned array.

Your case insensitive marker needs to be all by itself: "(?i)"

The rest that group is being ignored.

So far, so good. Keep learning!

;)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

If you get an error, there won't be an array returned (good idea to test @error and/or IsArray()). And test with Ubound() before you assume a certain number of elements in any returned array.

Your case insensitive marker needs to be all by itself: "(?i)"

The rest that group is being ignored.

So far, so good. Keep learning!

;)

Ok, from the help section "(?i: ... ) Case-insensitive non-capturing group." I thought that meant that I could put the ?i: at the front of the group, and it would not match case and would not capture that group.

Also, how do I test @error and isarray()?

I found a few instances of @error in example code, but the help file does not say anything other than I should check seterror. I tried what I had seen which was

if @error then
but it went straight to the else portion of the code.

However, I also tried

If Isarray($task) Then
which returns true, and executes the "Then" statement.

I assume this means this is an array, but I don't know if I am testing @error properly, and I can't find how I should test it in the help files. Is there some reference I could read on basic validation such as testing @error and Isarray()?

Oh, and thanks for the ubound suggestion, I have used that before and completely forgot.

Link to comment
Share on other sites

Ok, from the help section "(?i: ... ) Case-insensitive non-capturing group." I thought that meant that I could put the ?i: at the front of the group, and it would not match case and would not capture that group.

The group "(?i)" makes every group from there on case insensitive. The operative part of "(?i: ...)" is "non-capturing". "Capturing" here means matching it and adding it to the array. So you can pull some parts of the text but not others by having some groups be capturing, and others non-capturing. :evil:

Also, how do I test @error and isarray()?

I found a few instances of @error in example code, but the help file does not say anything other than I should check seterror. I tried what I had seen which was

if @error then
but it went straight to the else portion of the code.

However, I also tried

If Isarray($task) Then
which returns true, and executes the "Then" statement.

I assume this means this is an array, but I don't know if I am testing @error properly, and I can't find how I should test it in the help files. Is there some reference I could read on basic validation such as testing @error and Isarray()?

Oh, and thanks for the ubound suggestion, I have used that before and completely forgot.

Try this:
#include <Array.au3>

Global $aInput[2] = ["        1   Each W                  5:30 AM       c:\reboot.exe", _
        "        2   Each W                  5:30 AM       c:\reboot.exe"]

For $n = 0 To UBound($aInput) - 1
    $task = StringRegExp($aInput[$n], '([0-9]{1,2})(?i)(\s+Each [A-Z]{1,2}\s+[0-9]{1,2}:[0-9]{1,2} [A-Z]{2}\s+c:\\reboot.exe)', 1)
    If @error = 0 And IsArray($task) And UBound($task) >= 2 Then
        ConsoleWrite("ID = " & $task[0] & "; Info = " & $task[1] & @LF)
    Else
        ConsoleWrite($n & ":  Error" & @LF)
    EndIf
Next

Note the use of "\s+" instead of trying to include all the spaces between parts.

;)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

The group "(?i)" makes every group from there on case insensitive. The operative part of "(?i: ...)" is "non-capturing". "Capturing" here means matching it and adding it to the array. So you can pull some parts of the text but not others by having some groups be capturing, and others non-capturing. :evil:

Try this:

#include <Array.au3>

Global $aInput[2] = ["        1   Each W                  5:30 AM       c:\reboot.exe", _
        "        2   Each W                  5:30 AM       c:\reboot.exe"]

For $n = 0 To UBound($aInput) - 1
    $task = StringRegExp($aInput[$n], '([0-9]{1,2})(?i)(\s+Each [A-Z]{1,2}\s+[0-9]{1,2}:[0-9]{1,2} [A-Z]{2}\s+c:\\reboot.exe)', 1)
    If @error = 0 And IsArray($task) And UBound($task) >= 2 Then
        ConsoleWrite("ID = " & $task[0] & "; Info = " & $task[1] & @LF)
    Else
        ConsoleWrite($n & ":  Error" & @LF)
    EndIf
Next

Note the use of "\s+" instead of trying to include all the spaces between parts.

;)

Ok, that seems to have helped, it at least helped me figure out what was happening and what was not happening. Not an error, it just matches the first line, but not the second line. I took what you gave me and changed it to make the second part non-capturing, because I am just interested in that first number. However that helps because now I know my error checking was actually working, and the 1 is an actual match. When I tried your suggestion exactly as it was, I got a match on "1" and "Each W 5:30 AM c:\reboot.exe" but I did not get any matches on the second part, which I think should also match.

So far my code looks like this:

#include <Constants.au3>
#include <Array.au3>
AutoItSetOption("MustDeclareVars", 1)

dim $cmdresult
dim $line
dim $count
dim $test
dim $task
dim $arraylimit

;retrieve the scheduled tasks from the target machine
$cmdresult = Run('at \\lteis007', "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
Processwaitclose($cmdresult)
$line = string(StdoutRead($cmdresult))
;check the output from the AT command
msgbox(1,"test",$line)

$task=stringregexp($line,'([0-9]{1,2})(?i)(?:\s+Each [A-Z]{1,2}\s+[0-9]{1,2}:[0-9]{1,2} [A-Z]{2}\s+c:\\reboot.exe)',1)
if isarray($task) then 
    Else
    msgbox(1,"error","No matches found")
    ;Exit
EndIf
if @error>0 Then
    msgbox(1,"array error","no matches, array is invalid")
    EndIf
$arraylimit=ubound($task)
msgbox(1,"array limit",$arraylimit)
$count=0
while $count<$arraylimit
    msgbox(1,"regular expression output",$task[$count])
    $count=$count+1
    WEnd
Exit

I was running the Ifarray() and @error because I was not sure I was doing either right, so there is a lot of extra crap in there. As I look at your example and my code, and I see how your code outputs the matches from the regular expression, I think I have a few ideas of what I might be able to do to fix it. I am headed home for the day, but I think I will continue to play with this at home, it feels like I am making some simple mistake in my implementation, and that I am a simple fix away at this point.

Link to comment
Share on other sites

Try non regex solution:

$string = "1   Each W                  5:30 AM       c:\reboot.exe"&@CRLF&"2   Each W                  5:30 AM       c:\reboot.exe"
$lines = StringSplit($string,@CRLF)
$number = "" 
For $i = 1 To $lines[0]
    If StringInStr($lines[$i],"c:\reboot.exe") Then $number = $number & " - " & StringLeft($lines[$i],1)
Next
MsgBox(0,"",$number)

Hi ;)

Link to comment
Share on other sites

Try non regex solution:

$string = "1   Each W                  5:30 AM       c:\reboot.exe"&@CRLF&"2   Each W                  5:30 AM       c:\reboot.exe"
$lines = StringSplit($string,@CRLF)
$number = "" 
For $i = 1 To $lines[0]
    If StringInStr($lines[$i],"c:\reboot.exe") Then $number = $number & " - " & StringLeft($lines[$i],1)
Next
MsgBox(0,"",$number)
That nicely illustrates the inflexibility that can creep in when simplifying things. That fails on a two digit ID number, doesn't account for variable spaces in front of the ID in the original, and if the executable or it's path is different, etc.

I'm not saying it can't be fixed to work with simple string manipulation, just that this topic is now an exercise in learning RegExps because they are much more powerful and flexible, making them easier to use when the task is more complex.

;)

Edited by PsaltyDS
Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

I found a fix, although I am not sure if I should have needed to do this.

I placed the StringRegExp in a loop, and broke the output from the AT command into separate lines so that I could check them one at a time. I thought I could run the StringRegExp on the whole set of text, and output each of the matches, but this seemed to work. I am guessing the way I ran it, I was only getting the first match. For my own education, is there a way to return all of the matches, or is looping the best way?

Thank you for all the help. I am sure Mison's code could work, but the answer was so close there was no point in switching methods.

The finalized "test" code.

$cmdresult = Run('at \\lteis007', "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
Processwaitclose($cmdresult)
$line = string(StdoutRead($cmdresult))
;check the output from the AT command
msgbox(1,"test",$line)
;split the AT command results into individual lines to be parsed
$test=stringsplit($line,@lf)
;check for errors in the string split, if everything seems to have worked, begin parsing the output
if isarray($test) and @error=0 Then
    for $count=0 to ubound($test)-1
        msgbox(1,"string value",$test[$count])
        ;check each line for the targeted script
        $task=stringregexp($test[$count],'([0-9]{1,2})(?i)(?:\s+Each [A-Z]{1,2}\s+[0-9]{1,2}:[0-9]{1,2} [A-Z]{2}\s+c:\\reboot.exe)',1)
        if isarray($task) and @error=0 Then
            for $innercount=0 to ubound($task)-1
                msgbox(1,"regexp output",$task[$innercount])
            Next
        EndIf
        
    Next
EndIf
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...