Use Autohotkey variable in text snippet - autohotkey

After many times of seraching i could not find an answer regarding my use case on Google or Stack Overflow.
I'm heavily using Autohotkey snippets like this for email:
:*:emailsignature::
(
Email signature text
)
But sometimes i need to temporarily add some more text inside the existing snippet.
:*:emailsignature::
(
Email signature text
%datewithtext%
Email signature text
)
::datewithtext::*** Date with text ***
So what i was wishing for is to add a variable inside the snippet as shown above. And of course I've tried the variable syntax from AHK, but got all sorts of errors.
So hopefully someone can point my in the right direction or even better show me an example code.
Thanks in advance.

On top of all the other suggestions, I would suggest to prevent you having to write "emailsignature" to trigger the text expansion. Instead, I would use e.g. "es". This short string is unique enough with the \ as the closing character to never (seldom) collide. I use this trick for many long words.

You could try this as a solution
:*:emailsignature:: ; hotstrings expect a literal string on one line,
; but can be used like hotkeys as well.
FormatTime, Date
dateWithText =
( ; the continuation section below works when assigning to a variable
Email signature text
%Date%
Email signature text
)
Return
::datewithtext::
Send % dateWithText
Return
OR, you could get kind of fancy
; auto-execute section
V_EmailSignature := "myemail#yahoo.com"
V_MomEmail := "mom#yahoo.com"
V_StreetAddress := "123 Any Street`r`nAnytown, ID, 12345"
Return ; end auto-execute section
; HOTSTRINGS
:*:emailsignature::
:*:momemail::
:*:streetaddress::
FormatTime, Date
vName := regexReplace(A_ThisHotkey, "\W")
newText := V_%vName%
dateWithText := Join("`r`n", newText, Date, newText)
Return
::datewithtext::
Send % dateWithText
Return
Join(delim, Strs*) {
newStr := ""
for _, Str in Strs {
newStr .= (newStr ? Delim : "") . Str
}
Return newStr
}
Does that help you?

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.

AutoHotKey if clipboard contains in array value

I am making a script for validating wallet cryptocurrency.
so whenever I copy the address wallet and then I run the script. if the address wallet same as the array value, it will show msgbox that give information about the wallet name. if not it will show n/a.
but I have some problems, where the msgbox shows based many numbers of the array
here is my code
^q::
walletAddr := Object("wallet1", "0x01415e36ce36d07229abf8b0435669088319f656", "wallet2", "0x9d6fb140607e1727c1373624a97ba681ef54f5bk", "wallet3", "0x660f01a47efd305862bc598cad44d1966b376d67")
found := 0
for k, v in walletAddr
if ( clipboard == v ) {
MsgBox % k
found := 1
}
if !found
MsgBox, n/a
return
and I figure out that this problem isn't from the script. but from the array value.
I try to change the value to a simple word and it works perfectly
walletAddr := Object("wallet1", 0xFF0000, "wallet2", 0x0000FF,"wallet3", 0x00FF00)
I have no clue where the problems come from. maybe it's because of length value, value typedata, or others.
can someone help me figure out my problem? thank you
i found tricky way to make it work :D
just add string text ( i use = "wallet_" ) before value and before clipboard.

Converting numbers into timestamps (inserting colons at specific places)

I'm using AutoHotkey for this as the code is the most understandable to me. So I have a document with numbers and text, for example like this
120344 text text text
234000 text text
and the desired output is
12:03:44 text text text
23:40:00 text text
I'm sure StrReplace can be used to insert the colons in, but I'm not sure how to specify the position of the colons or ask AHK to 'find' specific strings of 6 digit numbers. Before, I would have highlighted the text I want to apply StrReplace to and then press a hotkey, but I was wondering if there is a more efficient way to do this that doesn't need my interaction. Even just pointing to the relevant functions I would need to look into to do this would be helpful! Thanks so much, I'm still very new to programming.
hfontanez's answer was very helpful in figuring out that for this problem, I had to use a loop and substring function. I'm sure there are much less messy ways to write this code, but this is the final version of what worked for my purposes:
Loop, read, C:\[location of input file]
{
{ If A_LoopReadLine = ;
Continue ; this part is to ignore the blank lines in the file
}
{
one := A_LoopReadLine
x := SubStr(one, 1, 2)
y := SubStr(one, 3, 2)
z := SubStr(one, 5)
two := x . ":" . y . ":" . z
FileAppend, %two%`r`n, C:\[location of output file]
}
}
return
Assuming that the "timestamp" component is always 6 characters long and always at the beginning of the string, this solution should work just fine.
String test = "012345 test test test";
test = test.substring(0, 2) + ":" + test.substring(2, 4) + ":" + test.substring(4, test.length());
This outputs 01:23:45 test test test
Why? Because you are temporarily creating a String object that it's two characters long and then you insert the colon before taking the next pair. Lastly, you append the rest of the String and assign it to whichever String variable you want. Remember, the substring method doesn't modify the String object you are calling the method on. This method returns a "new" String object. Therefore, the variable test is unmodified until the assignment operation kicks in at the end.
Alternatively, you can use a StringBuilder and append each component like this:
StringBuilder sbuff = new StringBuilder();
sbuff.append(test.substring(0,2));
sbuff.append(":");
sbuff.append(test.substring(2,4));
sbuff.append(":");
sbuff.append(test.substring(4,test.length()));
test = sbuff.toString();
You could also use a "fancy" loop to do this, but I think for something this simple, looping is just overkill. Oh, I almost forgot, this should work with both of your test strings because after the last colon insert, the code takes the substring from index position 4 all the way to the end of the string indiscriminately.

Get First Character of A_LoopFileName?

I'm trying to parse a filename and get the first character from it as a string to compare it to a previously inputted variable. My code looks like:
FileSelectFolder, WhichFolder ; Ask the user to pick a folder.
; Ask what letter you want to start the loop from
InputBox, UserInput, Start At What Letter?, Please enter a letter to start at within the folder (CAPITALIZE IT!)., , 450, 150
if ErrorLevel {
MsgBox, CANCEL was pressed.
ExitApp
} else {
inputted_letter = %UserInput%
tooltip %inputted_letter% ; Show the inputted letter
sleep, 2000
tooltip
}
Loop, %WhichFolder%\*.*
{
current_filename_full = %A_LoopFileName%
files_first_letter := SubStr(current_filename_full, 1, 1)
tooltip %files_first_letter% ; Show the file's first letter
sleep, 2000
tooltip
if files_first_letter != inputted_letter
continue
...
Right now, it clearly shows in the tooltips the user-entered capital letter, and then the first letter of each file name from within the selected folder, but for some reason when the two look alike, it doesn't recognize them as a match. I'm thinking maybe because technically A_LoopFileName is not of a string type? Or maybe the inputted letter doesn't match the type of the first filename's letter?
I want it to continue if the inputted letter and the first letter of the filename don't match, but if they do, to carry on with the rest of the script. Any ideas on how I can get these two to successfully match? Thanks!
Firstly, AHK doesn't really have types. At least not how you've experienced types in other languages.
So your assumption about "not being correct type" will pretty much always be wrong.
So the actual cause is because in a legacy if statement, the syntax is
if <name of variable> <operator> <legacy way of representing a value>
So you'd do it like this:
if files_first_letter != %inputted_letter%
You we're comparing if the variable files_first_letter is equal to the literal text inputted_letter.
However, I highly recommend you stop using legacy syntax. It's really just that old.
It'll differ horribly much from any other programming language and you run into confusing behavior like this. Expression syntax is what you want to use in AHK nowadays.
Here's your code snippet converted over to expression syntax in case you're interested:
FileSelectFolder, WhichFolder
;Forcing an expression like this with % in every parameter
;is really not needed of course, and could be considered
;excessive, but I'm doing it for demonstrational
;purposes here. Putting everything in expression syntax.
;also, not gonna lie, I always do it myself haha
InputBox, UserInput, % "Start At What Letter?", % "Please enter a letter to start at within the folder (CAPITALIZE IT!).", , 450, 150
if (ErrorLevel)
;braces indicate an expression and the non-legacy if statement
;more about this, as an expression, ErrorLevel here holds the value
;1, which gets evaluated to true, so we're doing
;if (true), which is true
{
MsgBox, % "CANCEL was pressed."
ExitApp
}
else
inputted_letter := UserInput ; = is never used, always :=
Loop, Files, % WhichFolder "\*.*"
;non-legacy file loop
;note that here forcing the expression statement
;with % is actually very much needed
{
current_filename_full := A_LoopFileName
files_first_letter := SubStr(current_filename_full, 1, 1)
if (files_first_letter != inputted_letter)
continue
}
Also you don't have to be concerned about case with !=, it'll always compare case insensitively.

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
}