ahk: how to read non txt file and save infos to variables? - autohotkey

i have a replay file from a game (world of tanks) and i want to read infos from it and store them to variables.
when i open the file with notepad there seems to be some xml "code" witch contains some of the infos i want and then there starts the replay file data so its only gibberish. example: http://pastebin.com/faBPUn1d
i tried to extract the first line with FileReadLine but the variable contains only crap :(
how can i read the file with ahk, store infos like "damageDealt": 9321 to a variable?
thank you for your help

This is a JSON data inside a binary file so use FileOpen function to open it.
There are two JSON blocks and each one is prefixed by its length (NumGet or File.ReadUInt or similar to the rescue) so you can use it extract the block and pass it to AutoHotkey-JSON parser.
And then you will be able to access the object hierarchically or enumerate it like any object:
result.personal["14337"].details["(9291360, 7169)"].damageDealt.
Example:
#include JSON.ahk ; download from https://github.com/cocobelgica/AutoHotkey-JSON
; read the data
f := fileOpen("14473423299267_usa_A02_M2_lt_thepit.wotreplay", "r")
f.seek(8)
data1 := JSON.load(f.read(f.readUInt()))
data2 := JSON.load(f.read(f.readUInt()))
f.close()
; write the data as pretty-formatted JSON
f := fileOpen("data1.json", "w"), f.write(JSON.dump(data1,,"`t")), f.close()
f := fileOpen("data2.json", "w"), f.write(JSON.dump(data2,,"`t")), f.close()
; load the first item of 'data2[1].personal' object into personalInfo
data2[1].personal._NewEnum().Next(k, personalInfo)
msgbox % "playerName: " data1.playerName "`n"
. "dateTime: " data1.dateTime "`n"
. "mapName: " data1.mapName "`n"
. "`n"
. "damageDealt: " personalInfo.damageDealt "`n"

Related

How to check what the first word in clipboard is?

Lets say my Cliboard variable is currently in this state:
Clipboard:= "-Classes Essay on Hobbes
I want to perform If conditions depending on the first block/word in the clipboard, in this case -Classes . Essentially doing something like below using FileAppend:
if "-diary"{
;Create file in /Diary/Entry 27.MD
}
Else if "-Classes"{
;Create file in /Classes/Essay on Hobbes.MD
}
I was able to find this page in the docs If Var in/contains MatchList - Syntax & Usage | AutoHotkey but its not positional, which means if the block -Classes is also present as part of the file name for some reason, my logic breaks.
I have taken the liberty to crosspost this question on other forums as well.
Any help would be greatly appreciated!
Or.. you can just:
Clipboard:= "-Classes Essay on Hobbes"
Gosub % subroutine := SubStr( Clipboard, 1, InStr( Clipboard, " " )-1 )
Clipboard:= "-diary diary example"
Gosub % subroutine := SubStr( Clipboard, 1, InStr( Clipboard, " " )-1 )
Return
-diary:
MsgBox % "Diary:`n" StrReplace( clipboard, subroutine " " )
;Create file in /Diary/Entry 27.MD
Return
-Classes:
MsgBox % "Classes:`n" StrReplace( clipboard, subroutine " " )
;Create file in /Classes/Essay on Hobbes.MD
Return
You might try StrSplit()
; Array := StrSplit(String , Delimiters, OmitChars, MaxParts)
clip_array := StrSplit(Clipboard, A_Space, , 1)
if clip_array[1] = "-diary"{
;Create file in /Diary/Entry 27.MD
}
Else if clip_array[1] = "-Classes"{
;Create file in /Classes/Essay on Hobbes.MD
}
Else {
MsgBox % "No match for " clip_array[1]
}
Described here https://www.autohotkey.com/docs/commands/StrSplit.htm and note the param for MaxParts which addresses how many "tokens" to look in to (keeping the rest in the last) if the clipboard is sufficiently large to matter (in which case I'm not sure any of the other answers address any better).
If the amount of text on the clipboard is enormous, that could cause lagging with the script loading all of that text into the script memory, just to check the first value. I'd recommend regexMatch since that can return a position and capture the word as well without parsing everything.
; for reference of regexMatch function
; regexMatch(Haystack, Needle, outputVar, startPos)
Fnd := regexMatch(Clipboard, "U)(\-[\w]+))", capSubStr, inStr(Clipboard, "-"))
if (Fnd==0) {
Msgbox, Didn't find a word on the Clipboard.
Return
}
checkVal := capSubStr1
if (checkVal=="-diary") {
;Create file in /Diary/Entry 27.MD
} Else if (checkVal=="-Classes") {
;Create file in /Classes/Essay on Hobbes.MD
}
Here is the basic reference for using regular expressions with AHK: https://www.autohotkey.com/docs/misc/RegEx-QuickRef.htm
That will give an idea as to what the above expression is actually looking for, if you are not already familiar with regex.

Looking up data from a file, and storing them as variables

I'm new to autohotkey and I can't figure out how to solve this. Any help is appreciated.
I have list.txt which includes ids and names like this:
list.txt:
123124 - whatever
834019 - sometext
3980 - afjalkfj
I need a function that can do the following
lookup(id, name){
** The function here should lookup for the id inserted
then save ONLY the data related to it in variable x (not the full line)
}
Example
lookup(834019, x)
%x% = sometext
Please help me to do this. Thanks!
What you need in this case are
FileRead to read the file's contents into a variable.
A parsing loop to parse the text of each line.
The StrSplit() function to split the text of each line into an
array of Substrings using the specified Delimiters.
The second parameter (name) is redundant in this case. You can omit it:
x := lookup(834019)
MsgBox, % x
MsgBox, % lookup(3980)
lookup(id) {
FileRead, Contents, list.txt ; read the file's contents into the variable "Contents"
if not ErrorLevel ; Successfully loaded.
{
Loop, parse, Contents, `n, `r ; parse the text of each line
{
word_array1 := StrSplit(A_LoopField," - ").1 ; store the first substring into the variable "word_array1"
word_array1 := Trim(word_array1, " `t") ; trim spaces and tabs in this variable
If (word_array1 = id)
{
name := StrSplit(A_LoopField," - ").2
name := Trim(name, " `t")
return name
}
}
Contents := "" ; Free the memory.
}
else
MsgBox, A problem has been encountered while loading the File Contents
}

Split String in Array into an array autohotkey

Trying to read a CSV file in Auto Hot Key and line by line split the line by "," to pull out the last two columns of each line. Currently just trying to get the string to split into an array. I can print each line with the line
MsgBox, A_LoopReadLine but cannot split the string inside of the variable.
Have tried StringSplit and StrSplit but I am sure the syntax is incorrect.
MyArray := Object()
Loop, read, %fileop%
{
MyArray.Insert(A_LoopReadLine) ; Append this line to the array.
index := 1
MsgBox, %A_LoopReadLine%
;MyArray.
;MsgBox, % StrSplit(A_LoopReadLine ,",")
}
Loop % MyArray.Length()
MsgBox % StrSplit(MyArray[A_Index],",")
Trying to read a CSV file in Auto Hot Key and line by line split the
line by "," to pull out the last two columns of each line.
MyArray := Object()
Loop, Read, %fileop%
MyArray[A_Index]:=StrSplit(A_LoopReadLine,",")
This will store your csv file in MyArray[row][column] format. E.g to access second item in fifth row: MyArray[5][2]
for k,v in MyArray
v.RemoveAt(1,v.Length()-2)
Above will remove all but last two items from each row.
Documentation:
https://autohotkey.com/docs/commands/For.htm
https://autohotkey.com/docs/objects/Object.htm#RemoveAt_v1121+
https://autohotkey.com/docs/objects/Object.htm#Length
Edit:
And to as to why your code did not work. It kinda did.
The thing is that StrSplit() returns object, array so with below line you were trying to display object in MsgBox, this is not allowed.
MsgBox % StrSplit(MyArray[A_Index],",")
This for example would work:
MsgBox % StrSplit(MyArray[A_Index],",")[1]

Replace a middle string in .bat file using AutoHotKey without deleting file

I need to edit standalone.bat file using ahk script. I want to increase my heap size using ahk so below is line where i have to change heap in my bat file. Now i have trying to edit this using StringReplace and FileAppend but FileAppend keeps on appending string to the end
from
set "JAVA_OPTS=-Dprogram.name=%PROGNAME% -Xms64M -Xmx1426M %JAVA_OPTS%"
to
set "JAVA_OPTS=-Dprogram.name=%PROGNAME% -Xms64M -Xmx1426M %JAVA_OPTS%"xms000M
I am new to .ahk, i have tried this using some search
Loop, read, C:\standalone.bat
{
Line = %A_LoopReadLine%
replaceto = xms000M
IfInString, Line, Xmx1426M
, Line, replaceto, %Line%, %replaceto%
FileAppend, %replaceto%`n
StringReplace FileAppend
}
Is it possible to replace middle string using ahk. thanks
Fileappend will always append to the end of a file. Why do you want to prevent a temporary deletion of your batch file?
Typically, in ahk, you'd do it like this..
batFile = C:\standalone.bat
output := ""
Loop, read, %batFile%
{
Line = %A_LoopReadLine%
IfInString, Line, Xmx1426M
{
StringReplace, Line, Line, Xmx1426M, xms000M
; note: Regular Expressions can be used like Line := regExReplace(Line, "...", "...")
}
output .= Line . "`n" ; note: this is the same as if to say output = %output%%Line%`n or output := output . line "`n"
}
FileDelete, %batFile%
FileAppend, %output%, %batFile%
This will delete your file for some little milliseconds, just to recreate it with the new content afterwards. I don't really see any difference to editing it without deletion, because in either way, you'll need write access to the file.
Some words about your code sample:
IfInString, Line, Xmx1426M
, Line, replaceto, %Line%, %replaceto%
will be interpreted as
"If the string 'Line' contains 'Xmx1426M , Line, replaceto, %Line%, %replaceto%'"
which does not make any greater sense.
FileAppend, %replaceto%\n is lacking a destination file.
StringReplace FileAppend: these are two commands without any further parameters. You must never put two non-function-commands in the same line!

FileAppend data loss in a loop

In a loop, I use FileAppend to add text to a file. In every iteration of the loop, the data is accumulated in a variable and FileAppend is called every n iterations of the loop to save the data. Very occasionally, after a FileAppend call, the data accumulated in the variable during the next iteration is lost. As it is very intermittent, I could not reproduce this behavior. It seems like if, in some situation, the script would need a delay after FileAppend. Is this a known issue? I've search AHK forums and this site without report of such issue.
Here is a piece of code where this happens:
Loop, %intMax% ; for each record in the collection
{
if !Mod(A_Index, intProgressIterations)
; update the progress bar and save the data every intProgressIterations
; (when intProgressIterations / A_Index = 0)
{
ProgressUpdate(A_index, intMax, strProgressText)
; update progress bar only every %intProgressIterations% iterations
FileAppend, %strData%, %strFilePath%
strData := ""
; save the data accumulated in strData and empty it
}
strData := strData . BuildData(objCollection[A_Index])
; build the data for this record and add it to strData
}
More precisely, it is the content of one (or more) iteration of the line strData := strData . BuildData(objCollection[A_Index]) that is lost.
Could be any number of things. The file could be locked, there could be an error in your BuildData function that causes it not to produce data.
I'd recommend checking the last modified date before and after you append the data.
If it's the same, you can either try again and/or notify the user.
As to your question about the delay, it shouldn't need it, the script does not continue to the next line of code until it finishes writing to the file.
Following findings about file locking, this code with error management will be safer:
Loop, %intMax% ; for each record in the collection
{
if !Mod(A_Index, intProgressIterations)
; update the progress bar and save the data every intProgressIterations
; (when intProgressIterations / A_Index = 0)
{
ProgressUpdate(A_index, intMax, strProgressText)
; update progress bar only every %intProgressIterations% iterations
Loop
{
FileAppend, %strData%, %strFilePath%
; save the data accumulated in strData and empty it after the loop
if ErrorLevel
Sleep, 20
}
until !ErrorLevel or (A_Index > 50) ; after 1 second (20ms x 50), we have a problem
if (ErrorLevel)
strError := strError . "Error writing line " . A_Index . " Error: #" . A_LastError . "`n"
strData := ""
}
strData := strData . BuildData(objCollection[A_Index])
; build the data for this record and add it to strData
}
As an added point to this issue (for future searches)... I found that trying to FileAppend within a loop when the output file is on Dropbox, will also cause data loss.
Dropbox will detect updates to the file during the early cycles of the loop, and then lock it while it sends the updated (updating) file to the Dropbox servers. I've tracked data loss in a text file as short as 150 lines of text.
The solution I used was to create a temp output file outside of the Dropbox-monitored main folder, and write to it instead. When the loop is complete, copy the temp file back to Dropbox, and then delete the temp file.
Here's an partial code example of how I did the switch with a completed temp file, after the loop had finished:
; Copy the Daily Scrub temp file to var holding the filepath to todo.txt, then delete the Daily Scrub temp file
FileCopy, C:\temp-dailyscrub.txt, %todoFilePathParse%, 1
FileDelete, C:\temp-dailyscrub.txt