AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Execute a string read from a file/contained in a variable?

 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help
View previous topic :: View next topic  
Author Message
afromonkey0



Joined: 13 Oct 2007
Posts: 24

PostPosted: Tue Jan 01, 2008 8:01 pm    Post subject: Execute a string read from a file/contained in a variable? Reply with quote

I used an app called 'game maker' for a while and it had a neat function called 'execute_string(string)' which would execute the string supplied as though it had been typed into the script at that place.
Is this possible with ahk? I had a look in the help file but it's hard to track down a function you don't know the name of.

If not, here is what i want to do, if there is another way. I want to have my script read a line from a text file and expand variable in the string. It picks the line randomly, to be less predictable. so the text file might look like this;

Hello %A_userName%
Nice to meet you %A_UserName%
Ah, %A_UserName%, good %timestring%
etc.

But it's currently giving me the variable name, not the contents.
Back to top
View user's profile Send private message
Mustang



Joined: 17 May 2007
Posts: 415
Location: England

PostPosted: Tue Jan 01, 2008 8:55 pm    Post subject: Reply with quote

I had the same problem as you when I attempted this
Not able to find a solution I took a different approach

Create a file called "Lines.ahk" which contains the following:
Code:
Line1 = Hello %A_userName%
Line2 = Nice to meet you %A_UserName%
Line3 = Ah, %A_UserName%, good %timestring%

Then for your main script try this code:
Code:
#Include Lines.ahk

Loop
{
    If ( Line%A_Index% = "" )
    {
        Break
    }
    TotalLines := A_Index
}

Loop
{
    Random, RandomLine, 1, %TotalLines%
    MsgBox, % Line%RandomLine%
}
Return
Back to top
View user's profile Send private message
engunneer



Joined: 30 Aug 2005
Posts: 6847
Location: Pacific Northwest, US

PostPosted: Wed Jan 02, 2008 5:52 am    Post subject: Reply with quote

see
http://www.autohotkey.com/forum/viewtopic.php?t=3332
and
http://www.autohotkey.com/forum/viewtopic.php?t=25867
_________________
Unless otherwise noted, all code is untested.
Common Answers: 1.(Loops, Viruses, etc.) 2. Search 3.RTFM
Back to top
View user's profile Send private message Visit poster's website
DerRaphael



Joined: 23 Nov 2007
Posts: 604
Location: 127.0.0.1

PostPosted: Wed Jan 02, 2008 10:24 am    Post subject: Reply with quote

this should help you:

msg.txt
Code:

hello %A_UserName%
Nice to meet you %A_UserName%
Ah, %A_UserName% , good %timestring%


test.ahk
Code:
FileRead, messages, msg.txt
timestring := "whatever"
messages   := RegExReplace(messages, "\n", "`n", count) ; count lines
random, rnd, 1, %count% ; get random value in rnd
count := 0 ; reset count
loop, parse, messages, `n, `r ; parse read lines
{
  count++ ; increment count
  if (count=rnd) {
    message := A_LoopField
  }
}
; this is the trick - it transforms the read lines into expression
transform, message, deref, % message
msgbox % message
return


using above method u must ensure that in msg.txt last line has a carriage return - without the carriage return the line wont be counted and therefor never shown

hope it helps
derRaphael
_________________
Back to top
View user's profile Send private message
afromonkey0



Joined: 13 Oct 2007
Posts: 24

PostPosted: Wed Jan 02, 2008 10:55 am    Post subject: Thanks guys Reply with quote

Thanks that's great. I think all of those would work.
Engunneer: I just realised that what i want to do is execute code dynamically, i didn't realise that was the phrase for it. I've even read that thread before. Bonehead. Rolling Eyes
Anyway thanks I'll try those and get back
Back to top
View user's profile Send private message
afromonkey0



Joined: 13 Oct 2007
Posts: 24

PostPosted: Wed Jan 02, 2008 11:07 am    Post subject: Reply with quote

I tried DerRaphael's idea first and it works perfectly! Thanks mate.
quick speed question through. Which of these is likely to work quicker for a file of about 100 lines?

Code:
FileRead, messages, msg.txt
messages   := RegExReplace(messages, "\n", "`n", count)

or
Code:
loop, read, msg.txt
{
count += 1
}

because i've been using the latter, but if the former is faster i will change it.
Thanks again guys, this forum is great.
Back to top
View user's profile Send private message
Mustang



Joined: 17 May 2007
Posts: 415
Location: England

PostPosted: Wed Jan 02, 2008 12:34 pm    Post subject: Reply with quote

If only I had know about "Transform,, Deref" before now
Thanks DerRaphael
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 2739
Location: Australia, Qld

PostPosted: Wed Jan 02, 2008 1:27 pm    Post subject: Reply with quote

Transform,,Deref is definitely the fastest. All it does is expand variable references and escape sequences.

The first link in engunneer's post is for dynamically executing a command, and the second demonstrates a way to generate and run a script without using a temporary file. It seems both are overkill for what you want. Smile
Back to top
View user's profile Send private message
DerRaphael



Joined: 23 Nov 2007
Posts: 604
Location: 127.0.0.1

PostPosted: Wed Jan 02, 2008 1:42 pm    Post subject: Reply with quote

this is a quick test for making a QPC for three count lines methodes:

the one i indtroduced
the one from afromonkey0
and a tweaked one based on afromonkey0s

i've run the test several times and as a conclusion, i can say that
my provided function is no everytime the fastest with smaller files, but in general, especially when handling larger text files (2000+ lines) it is definitly faster.

tested on win2k@1000 GHz (my lil laptop)

here's the source:
Code:

MsgBox % "The test will be executed 10 Times `n"
       . "Each round the tst.txt will grow by 1000 Lines`n"
       . "Press OK to continue."

if (FileExist("tst.txt")) {
   FileDelete, tst.txt
   if (ErrorLevel) {
      MsgBox % "FileDelete resulted Errorlevel " ErrorLevel
   }
}

Loop, 10
{
txt := ""
Loop, 1000
   txt .= A_Index "`r`n"

DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore)
fileAppend, %txt%, tst.txt
FileRead, messages, tst.txt
messages   := RegExReplace(messages, "\n", "`n", count)
DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter)
res1 := CounterAfter - CounterBefore

count:=0
DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore)
loop, read, tst.txt
{
   count += 1
}
DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter)
res2 := CounterAfter - CounterBefore

count:=0
DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore)

loop, read, tst.txt
   count++

DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter)
res3 := CounterAfter - CounterBefore

MsgBox,64, % "Conclusion for reading " count " lines"
         , % "Method One (FileRead, RegExReplace) took " res1 " QPC time`n"
           . "Method Two (Loop, OTB count+=1) took " res2 " QPC time`n"
           . "Method Three (Loop, simple count++) took " res3 " QPC time`n"
}


One funny thing though - when i add two spaces in front of 3rd methods loop command and the count++ increment the method gets slower than anything by factor 10

greets
derRaphael
_________________
Back to top
View user's profile Send private message
afromonkey0



Joined: 13 Oct 2007
Posts: 24

PostPosted: Wed Jan 02, 2008 2:00 pm    Post subject: Reply with quote

That's a pretty neat testing script.

Quote:
my provided function is no everytime the fastest with smaller files, but in general, especially when handling larger text files (2000+ lines) it is definitly faster.


I found that for small files (<1000 lines) my method was a good deal faster (in this case just over 1/3 the time),

1000 lines:
Method One (FileRead, RegExReplace) took 15913 QPC time
Method Two (Loop, OTB count+=1) took 5711 QPC time
Method Three (Loop, simple count++) took 4019 QPC time

but for larger files your way became much much faster.

Since my files are only a few hundred lines, i'll stick with my one, but i will change my count += 1 to a count++. What is the difference between those anyway?
Back to top
View user's profile Send private message
DerRaphael



Joined: 23 Nov 2007
Posts: 604
Location: 127.0.0.1

PostPosted: Wed Jan 02, 2008 3:53 pm    Post subject: Reply with quote

afaik its about internal how ahk interpreter deals with it.

i think it was in help file, where i read about, that having a ++ operand is slightly faster than defining +=1

greets
derRaphael
_________________
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 2739
Location: Australia, Qld

PostPosted: Thu Jan 03, 2008 1:55 am    Post subject: Reply with quote

DerRaphael wrote:
i've run the test several times and as a conclusion, i can say that
my provided function is no everytime the fastest with smaller files, but in general, especially when handling larger text files (2000+ lines) it is definitly faster.
Was yours the loop method? When I run your benchmark script, it is consistently slower than the FileRead method...
Quote:
One funny thing though - when i add two spaces in front of 3rd methods loop command and the count++ increment the method gets slower than anything by factor 10
That must've been a freak coincidence, since AutoHotkey strips leading and trailing whitespace when it loads the file.
afromonkey0 wrote:
Since my files are only a few hundred lines, i'll stick with my one, but i will change my count += 1 to a count++. What is the difference between those anyway?
There is no difference, assuming they are each on their own line. If your benchmarks show different, it is likely by coincidence.
Code:
EnvAdd,a,1
a+=1
a++
++a
ListLines
Pause
AutoHotkey optimizes ++ by converting it to ACT_ADD (i.e. EnvAdd) if it is the only operation on the line.


Below, I've made the following changes to DerRaphael's benchmark script:
  • Use QueryPerformanceFrequency to get the performance counter's frequency (units per second) in order to display more meaningful results.
  • Don't bother generating txt in each round, since it is the same every time (and is never timed.)
  • Use longer lines in txt to be more representative of a real file.
  • Append to the file before starting the counter for the RegExReplace benchmark Exclamation
  • Don't include braces for the "count+=1" loop, since braces take time to process (though very little.) This makes the comparison of += to ++ more fair (though it is still pointless since they are both exactly the same thing.)
  • For easier comparison:
    • Divide the results of each round by the round number (show number of seconds per 1k lines.)
    • Show the results at the end of all rounds, with the individual times for each round and the average of all rounds.
  • For each test in each round, iterate 100 (or so) times to iron out coincidental inconsistencies.
  • SetBatchLines,-1 to make the tests complete in half the time. (By default, the script sleeps for 10ms every 10ms.)
  • Add StringReplace as an alternative to RegExReplace. Smile

Code:

MsgBox % "The test will be executed 10 Times `n"
       . "Each round the tst.txt will grow by 1000 Lines`n"
       . "Press OK to continue."

if (FileExist("tst.txt")) {
   FileDelete, tst.txt
   if (ErrorLevel) {
      MsgBox % "FileDelete resulted Errorlevel " ErrorLevel
   }
}

; get the performance counter's frequency (units per second)
DllCall("QueryPerformanceFrequency","int64*",freq)

; no need to do this each round
Loop, 1000
   txt .= A_Index ": The quick brown fox jumped over the lazy dog.`r`n"

inner_iterations = 100

; make the test go faster.
SetBatchLines, -1

Loop, 10
{
    ; this should not be included in the benchmark for RegExReplace!
    fileAppend, %txt%, tst.txt
   
    DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore)
    Loop, %inner_iterations% {
        FileRead, messages, tst.txt
        messages   := RegExReplace(messages, "\n", "`n", count)
    }
    DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter)
    res1 .= (CounterAfter - CounterBefore) / freq / inner_iterations / A_Index "`t"
ToolTip %A_Index%. First test complete.
    DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore)
    count:=0
    Loop, %inner_iterations% {
        loop, read, tst.txt
           count += 1
    }
    DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter)
    res2 .= (CounterAfter - CounterBefore) / freq / inner_iterations / A_Index "`t"
ToolTip %A_Index%. Second test complete.
    DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore)
    count:=0
    Loop, %inner_iterations% {
        loop, read, tst.txt
           count++
    }
    DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter)
    res3 .= (CounterAfter - CounterBefore) / freq / inner_iterations / A_Index "`t"
ToolTip %A_Index%. Third test complete.
    DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore)
    Loop, %inner_iterations% {
        FileRead, messages, tst.txt
        StringReplace, messages, messages, `n, `n, UseErrorLevel
        count := ErrorLevel
    }
    DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter)
    res4 .= (CounterAfter - CounterBefore) / freq / inner_iterations / A_Index "`t"
ToolTip %A_Index%. Fourth test complete.
}

Loop, 4 {   ; calculate average times
    total = 0
    Loop, Parse, res%A_Index%, %A_Tab%
        if A_LoopField !=
            total += A_LoopField
    avg%A_Index% := total/10,"average"
}

FileGetSize, size, tst.txt
MsgBox,64, % "Conclusion @ " size " bytes"
         , % "Method One (FileRead, RegExReplace),`tavg "       avg1 "`n" res1
           . "`nMethod Two (Loop, count+=1),`tavg "             avg2 "`n" res2
           . "`nMethod Three (Loop, count++),`tavg "            avg3 "`n" res3
           . "`nMethod Four (FileRead, StringReplace),`tavg "   avg4 "`n" res4

The results I get are:
Code:
Method One (FileRead, RegExReplace),    avg 0.000676
0.000727   0.000655   0.000639   0.000669   0.000683   0.000680   0.000671   0.000673   0.000667   0.000700
Method Two (Loop, count+=1),            avg 0.001858
0.001856   0.001875   0.001818   0.001834   0.001884   0.001859   0.001894   0.001839   0.001871   0.001846
Method Three (Loop, count++),           avg 0.001838
0.001792   0.001830   0.001819   0.001826   0.001842   0.001864   0.001854   0.001857   0.001847   0.001848
Method Four (FileRead, StringReplace),  avg 0.000454
0.000439   0.000421   0.000427   0.000445   0.000466   0.000464   0.000466   0.000462   0.000463   0.000487

This shows FileRead + RegExReplace as a clear winner over Loop + count++. It also shows StringReplace is faster than RegExReplace.


As I side-note, my own benchmarks usually look like:
Code:
i = 1000000
T()  ; set initial counter
Loop, %i%
    do something funky
t1 := T()/i  ; time since last T() call divided by i

Loop, %i%
    do something else to compare
t2 := T()/i

MsgBox test 1: %t1%`ntest 2: %t2%

; this is in my function library:
T() {
    Static freq, last_count
    if !freq
        DllCall("QueryPerformanceFrequency","int64*",freq)
    DllCall("QueryPerformanceCounter","int64*",count)
    return (count-last_count)/freq, last_count:=count
}
Back to top
View user's profile Send private message
DerRaphael



Joined: 23 Nov 2007
Posts: 604
Location: 127.0.0.1

PostPosted: Thu Jan 03, 2008 6:21 am    Post subject: Reply with quote

thanks lexikos for pointing at the fileappend inside the 1st loop i somehow overlooked it - since i was just copy & pasting the qpc around it together.
btw my method was the fileread regexed one

i left the curly brackets to keep the origin loop from poster and set up a loop without those just to compare

i also thought bout the stringreplace method but couldn't get it done, since i always brought in typos and didnt see 'em it endet up in just not workin' frustrated i came up with regex knowing it'd be slower than stringreplace
i guess, i am just too tired to think straight .... or i got distracted or both ;/

well, its half past 7 here localtime and im up for more than 26 hours, i think i get some sleep

thanks again
derRaphael
_________________
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help All times are GMT
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group