Jump to content

Using ambiguous characters in a string split


Go to solution Solved by jchd,

Recommended Posts

My goal is to use a hotkey to Send() text acquired from the GUICtrlRead() of an edit field on a GUI.

So far, so easy.

The challenge: Midway through the string returned by GUICtrlRead() (and sometimes more than once), will be a string like {MouseClick("left", x, y)}. When the program reaches that part of the string, I would like it to click at the coordinates specified; then, continue with SEND().

My original plan was to use StringSplit() with the clicks as delimiters. In theory, to loop through the array of strings, clicking when necessary. My plan doesn't seem like it will work because x and y will be unpredictable numbers, and I'm not sure how to overcome that impediment. I welcome any thoughts.

 

Edit: This is my code so far.

#include <GUIConstants.au3>

AutoItSetOption("MustDeclareVars", 1)
Opt("GUIOnEventMode", 1)

Global $aGUI = GUICreate("", 300, 100)
Global $Text_Field = GUICtrlCreateEdit("Hello{MouseClick('left',100,100)} world{MouseClick('left',200,200)}.", 0, 0, 300, 100, $ES_MULTILINE+$WS_VSCROLL)
GUISetOnEvent($GUI_EVENT_CLOSE, "GUI_Events")
GUISetOnEvent($GUI_EVENT_MINIMIZE, "GUI_Events")
GUISetOnEvent($GUI_EVENT_RESTORE, "GUI_Events")
GUISetState(@SW_SHOW,$aGUI)
HotKeySet("{F1}", "F1_HotKey")

While 1
    Sleep(10)
Wend

Func GUI_Events()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            Exit
    EndSelect
EndFunc

Func F1_HotKey()
    Local $Text_To_Send = GUICtrlRead($Text_Field)
    Local $Array_Of_Text_To_Send = StringSplit($Text_To_Send,"") ;but somehow separate out clicks
    For $i = 1 to $Array_Of_Text_To_Send[0] ;and sequence them in this loop
        Send($Array_Of_Text_To_Send[$i])
    Next
EndFunc

 

Edited by baconaise
Added code to use as template
Link to comment
Share on other sites

Could you post some code that shows what you've got so far? If you're parsing a whole string like "First click{MouseClick('left',100,200)}Second click{MouseClick('left',200,400)}", then I assume that you're using Send to send 1 key at a time and checking if you've reached a command instead of character? 

I would recommend using _StringBetween when you reach a special character, like "{" to find your command, execute it, then continue with your Send.

Here's an example of how I would do something like that, though it can definitely get a bit messy:

#include <String.au3>
; String of characters to send and commands to run
Global $sString = "First click{MouseClick('left',100,200)}Second click{MouseClick('left',200,400)}"
ConsoleWrite('$sString original: ' & $sString & @CRLF)

; Get all commands that are in the string, using {} as the boundries
Global $aCommands = _StringBetween($sString, '{', '}')

; Loop through each command in the string, and replace the command (not the {}) with the index for that command
For $iIndex = 0 To UBound($aCommands) -1
    $sString = StringReplace($sString, $aCommands[$iIndex], $iIndex, 1) ; Make sure that Occurance is 1, so that you're only replacing the first occurance of that command
Next
ConsoleWrite('$sString commands removed: ' & $sString & @CRLF)

; Build the Send list of characters, note this still has {#} in it, so those will have their own indexes
Global $aCharacters = StringSplit($sString, '', 3)

Global $bCommand = False ; This will be used to know that we're not sending the characters, and so that we're...
Global $iCommandIndex = '' ; Building this index from the $aCharacters array between { and }

; Now loop through the string to Send your keys, and when found, get the command index and execute the command
For $iChar = 0 To UBound($aCharacters) - 1
    ; Start of a command index
    If $aCharacters[$iChar] = '{' Then
        ConsoleWrite('Command found at char index: ' & $iChar & @CRLF)
        $iCommandIndex = '' ; Make sure that our index is reset
        $bCommand = True ; Notice that we're about to process a command
        ContinueLoop ; We can move to the next character
    EndIf

    ; If we're in between a command string { # }, build the $iCommandIndex string to get the correct index for $aCommands
    If $bCommand Then
        If $aCharacters[$iChar] = '}' Then ; End of the command index, so now we can execute
            $bCommand = False ; Go back to Send'ing characters
        ElseIf IsNumber(Int($aCharacters[$iChar])) Then ; Make sure that what we're building for our index is a number
            $iCommandIndex &= $aCharacters[$iChar] ; Build the index string
        Else ; Something unexpected
            ConsoleWrite('Possibly badly formatted command index: ' & $aCharacters[$iChar] & @CRLF)
        EndIf

        ; This means that we've processed the entire { ### } section and *should* have the complete index string
        If $bCommand = False Then
            ConsoleWrite('Executing command: ' & $iCommandIndex & ', ' & $aCommands[$iCommandIndex] & @CRLF)
            Execute($aCommands[$iCommandIndex]) ; Do your command
        EndIf
        ContinueLoop ; Go to next loop since we don't want to send }
    EndIf

    ; Do your normal Send
    Send($aCharacters[$iChar])
Next

 

We ought not to misbehave, but we should look as though we could.

Link to comment
Share on other sites

@mistersquirrle In my opinion, the {} as a command identifier, inside the string line, is not a good idea,
because it uses from Send() for special characters e.g. {ENTER}, {UP} etc.

here is my approach

SendPlus('@CMD Run("Notepad.exe")|@CMD Sleep(300)|@CMD WinActivate("[CLASS:Notepad]")')
SendPlus('@CMD WinSetState("[CLASS:Notepad]", "", @SW_MAXIMIZE)|send something{Enter 2}')
SendPlus('Maximize window{Enter}')
SendPlus('Here is more text{Enter 2}... and give some time{Enter}')
SendPlus('@CMD sleep(1000)|First click...{Enter}|@CMD MouseClick("left",100,200)|@CMD sleep(500)|Second click|@CMD MouseClick("left",200,400)')

;----------------------------------------------------------------------------------------
Func SendPlus($String)
    Local $Spl = StringSplit($String, "|", 1)
    ConsoleWrite("" & @CRLF)
    For $i = 1 To $Spl[0]
        If StringLeft($Spl[$i], 5) = "@CMD " Then
            Local $SplString = StringTrimLeft($Spl[$i], 5)
            ConsoleWrite($i & ") Comand:" & $SplString & @CRLF)
            Execute($SplString)
        Else
            ConsoleWrite($i & ") String:" & $Spl[$i] & @CRLF)
            Send($Spl[$i])
        EndIf
    Next
EndFunc   ;==>SendPlus

 

 

Edited by ioa747

I know that I know nothing

Link to comment
Share on other sites

19 hours ago, mistersquirrle said:

Could you post some code that shows what you've got so far?

Certainly! This is my basic idea:

#include <GUIConstants.au3>

AutoItSetOption("MustDeclareVars", 1)
Opt("GUIOnEventMode", 1)

Global $aGUI = GUICreate("", 300, 100)
Global $Text_Field = GUICtrlCreateEdit("Hello{MouseClick('left',100,100)} world{MouseClick('left',200,200)}.", 0, 0, 300, 100, $ES_MULTILINE+$WS_VSCROLL)
GUISetOnEvent($GUI_EVENT_CLOSE, "GUI_Events")
GUISetOnEvent($GUI_EVENT_MINIMIZE, "GUI_Events")
GUISetOnEvent($GUI_EVENT_RESTORE, "GUI_Events")
GUISetState(@SW_SHOW,$aGUI)
HotKeySet("{F1}", "F1_HotKey")

While 1
    Sleep(10)
Wend

Func GUI_Events()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            Exit
    EndSelect
EndFunc

Func F1_HotKey()
    Local $Text_To_Send = GUICtrlRead($Text_Field)
    Local $Array_Of_Text_To_Send = StringSplit($Text_To_Send,"") ;but somehow separate out clicks
    For $i = 1 to $Array_Of_Text_To_Send[0] ;and sequence them in this loop
        Send($Array_Of_Text_To_Send[$i])
    Next
EndFunc

 

Link to comment
Share on other sites

  • Solution

Try this version :

Func F1_HotKey()
    Local $Text_To_Send = GUICtrlRead($Text_Field)
    Local $Array_Of_Text_To_Send = StringRegExp($Text_To_Send,"([^{]*)({[^}]*})*", 3)
    For $s In $Array_Of_Text_To_Send
        If StringLeft($s, 1) = "{" Then
            Execute(StringRegExpReplace($s, "[{}]", ""))
        Else
            Send($s)
        EndIf
    Next
EndFunc

 

Edited by jchd

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

5 minutes ago, jchd said:

Try this version :

Func F1_HotKey()
    Local $Text_To_Send = GUICtrlRead($Text_Field)
    Local $Array_Of_Text_To_Send = StringRegExp($Text_To_Send,"([^{]*)({[^}]*})", 3)
        If StringLeft($s, 1) = "{" Then
            Execute(StringRegExpReplace($s, "[{}]", ""))
        Else
            Send($s)
        EndIf
    Next
EndFunc

 

Hello!

I had to remove Next because there wasn't a For for it.

I'm not sure where you got $s from, but I didn't get anywhere by declaring it prior to the function.

I'll admit I'm reasonably mystified by StringRegExp. I've not used it before.

Link to comment
Share on other sites

Sorry, this resulted from running the code. I've restored it in the post above.

When run, it sends string to the point where the mouse was set in the previous loop. Unfortunately this " world" text deleted the For line in Scite!

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

Try the changed posted version

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

Expression tester with pattern breakdown is here: https://regex101.com/r/483ZUH/1

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

You're welcome!

Now you have another silver bullet for your gun: regexes. Enjoy!

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

@jchd Would it be difficult to augment it in such a way that the other Send tricks still work (like {TAB})?

Ideally, I'd like those to still work.

Ideally ideally, I'd also like to be able to put in a command like {SLEEP 500} and have it sleep half a second when it gets to that point in the text.

Link to comment
Share on other sites

The current code can accept {sleep 500} as well without change.

But if you intend to use the same separator pair (curly brackets {}) for BOTH AutoIt statements AND Send special syntaxes, then you'll have to test the string content against all of the special syntaxes listed in Send() help. Very cumbersome!

Better use a distinct separator for AutoIt statements and leave {} alone. Choose it so that it can't reasonably occur in texts nor in statements. You have the full Unicode BMP (around 64k codepoints) to choose from, but restricting to a number of ASCII everyone can compose easily seems a good idea, like ~ # | ^ % § < > ¤

Example with #

#include <GUIConstants.au3>

AutoItSetOption("MustDeclareVars", 1)
Opt("GUIOnEventMode", 1)

Global $aGUI = GUICreate("", 300, 100)
Global $Text_Field = GUICtrlCreateEdit("#sleep 150#Hello#MouseClick('left',100,100)# world#MouseClick('left',200,200)#.#send({TAB})#", 0, 0, 300, 100, $ES_MULTILINE+$WS_VSCROLL)
GUISetOnEvent($GUI_EVENT_CLOSE, "GUI_Events")
GUISetOnEvent($GUI_EVENT_MINIMIZE, "GUI_Events")
GUISetOnEvent($GUI_EVENT_RESTORE, "GUI_Events")
GUISetState(@SW_SHOW,$aGUI)
HotKeySet("{F1}", "F1_HotKey")

While 1
    Sleep(10)
Wend

Func GUI_Events()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            Exit
    EndSelect
EndFunc

Func F1_HotKey()
    Local $Text_To_Send = GUICtrlRead($Text_Field)
    Local $Array_Of_Text_To_Send = StringRegExp($Text_To_Send,"([^#]*)(#[^#]*#)*", 3)
    For $s In $Array_Of_Text_To_Send
        If StringLeft($s, 1) = "#" Then
            Execute(StringRegExpReplace($s, "#", ""))
        Else
            Send($s)
        EndIf
    Next
EndFunc

Using # (for instance) as the sole separator is even easier than dealing with a pair.

Edited by jchd
Fixed a typo

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

@jchd I've been playing with this since yesterday, and I can't seem to sort out the regular expression quite properly.

If I use your first recommended ([^#]*)(#[^#]*#), it lets me use multiple clicks and sleeps in a row, but forgets to type anything after the last click/sleep.

If I use your amended ([^#]*)(#[^#]*#)*, it types the stuff at the end, but doesn't allow for consecutive slicks/sleeps.

Is there some way to allow consecutive clicks/sleeps while still making sure to type the stuff at the end?

 

Edit: I think I fixed it.

Func F1_HotKey()
    Local $Text_To_Send = GUICtrlRead($Text_Field)
    Local $Array_Of_Text_To_Send = StringRegExp($Text_To_Send,"([^#]*)(#[^#]*#)([^#]*)", 3)
    For $s In $Array_Of_Text_To_Send
        If StringLeft($s, 1) = "#" Then
            Execute(StringRegExpReplace($s, "#", ""))
        Else
            Send($s)
        EndIf
    Next
EndFunc

 

Edited by baconaise
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...