 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
afromonkey0
Joined: 13 Oct 2007 Posts: 24
|
Posted: Tue Jan 01, 2008 8:01 pm Post subject: Execute a string read from a file/contained in a variable? |
|
|
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 |
|
 |
Mustang
Joined: 17 May 2007 Posts: 415 Location: England
|
Posted: Tue Jan 01, 2008 8:55 pm Post subject: |
|
|
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 |
|
 |
engunneer
Joined: 30 Aug 2005 Posts: 6847 Location: Pacific Northwest, US
|
|
| Back to top |
|
 |
DerRaphael
Joined: 23 Nov 2007 Posts: 604 Location: 127.0.0.1
|
Posted: Wed Jan 02, 2008 10:24 am Post subject: |
|
|
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 |
|
 |
afromonkey0
Joined: 13 Oct 2007 Posts: 24
|
Posted: Wed Jan 02, 2008 10:55 am Post subject: Thanks guys |
|
|
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.
Anyway thanks I'll try those and get back |
|
| Back to top |
|
 |
afromonkey0
Joined: 13 Oct 2007 Posts: 24
|
Posted: Wed Jan 02, 2008 11:07 am Post subject: |
|
|
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 |
|
 |
Mustang
Joined: 17 May 2007 Posts: 415 Location: England
|
Posted: Wed Jan 02, 2008 12:34 pm Post subject: |
|
|
If only I had know about "Transform,, Deref" before now
Thanks DerRaphael |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2739 Location: Australia, Qld
|
Posted: Wed Jan 02, 2008 1:27 pm Post subject: |
|
|
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.  |
|
| Back to top |
|
 |
DerRaphael
Joined: 23 Nov 2007 Posts: 604 Location: 127.0.0.1
|
Posted: Wed Jan 02, 2008 1:42 pm Post subject: |
|
|
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 |
|
 |
afromonkey0
Joined: 13 Oct 2007 Posts: 24
|
Posted: Wed Jan 02, 2008 2:00 pm Post subject: |
|
|
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 |
|
 |
DerRaphael
Joined: 23 Nov 2007 Posts: 604 Location: 127.0.0.1
|
Posted: Wed Jan 02, 2008 3:53 pm Post subject: |
|
|
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 |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2739 Location: Australia, Qld
|
Posted: Thu Jan 03, 2008 1:55 am Post subject: |
|
|
| 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
- 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.
| 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 |
|
 |
DerRaphael
Joined: 23 Nov 2007 Posts: 604 Location: 127.0.0.1
|
Posted: Thu Jan 03, 2008 6:21 am Post subject: |
|
|
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 |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|