Alphabetizing a List - autohotkey

I'm looking for a way to truly alphabetize a list. Assuming it's a list of basic words, such as:BlackGreenThe RedBlueWaxyLivingPorousSolidLiquidVioletIs there a way to modify this code to alphabetize the list where "The Red" comes before "Solid"? Here's what I have so far:
SaveVar=%ClipboardAll%
Clipboard=
Send ^c
ClipWait, 0.5
Sort clipboard, CL
;Process exceptions
Sort := RegExOmit (Sort, "The")
Send ^v
Sleep 100
Clipboard=%SaveVar%
SaveVar=
return

Write a custom comparison function that ignores the starting "The " substring.
list = Black`nGreen`nThe Red`nBlue`nWaxy`nLiving`nPorous`nSolid`nLiquid`nViolet`nThe Azure
Sort , list , F Compare
MsgBox, %list%
Compare( a , b )
{
arem := RegExReplace(a, "A)The " , "" )
brem := RegExReplace(b, "A)The " , "" )
return arem > brem ? 1 : arem < brem ? -1 : 0
}
Regular expressions are used to remove the substring "The " from the string and the result stored in a temporary string, which is then used for comparison.
The substring must start at the beginning of the string, regex option A), and must include a space immediately after The.

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.

Why is the key of my Associative Array a reference to a string and not the string itself?

I have the following string that contains product barcodes:
4016241030924;4016241030924;8710624237479;5900951254741;8710398162939;8710398162939;8710398162939;8710398162939;8710398162939;8710398162939;8710398162939;8710398162939;8710624296933;8710624296872;8710624223885;8710624223885;8711000341001;8711000341001;8711000341001;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260453;
What I want to do is:
Split the string by ;
Create an Associative Array where the key is the barcode and the value is the count of the barcode
Loop through the Associative Array and print the key (= barcode) and the value (= count)
Here's what I am trying:
BarcodesAssArray := Array()
BarcodeArray := StrSplit(fileContent, ";")
Loop % BarcodeArray.MaxIndex() - 1 {
thisBarcode := BarcodeArray[a_index]
; Check if barcode already exists
if (BarcodesAssArray[thisBarcode]) {
BarcodesAssArray[thisBarcode] := BarcodesAssArray[thisBarcode] + 1
} else {
BarcodesAssArray[thisBarcode] := 1
}
}
For key, value in BarcodesAssArray
MsgBox, %key% = %value%
But instead of the key being the barcode it is some sort of reference to the barcode. This is what I get:
-333809963 = 1
204486651 = 8
430547597 = 2
430561191 = 1
430584127 = 9
43084165 = 1
...
What I expect to get is:
4016241030924 = 2
8710624237479 = 1
8710398162939 = 8
...
What should I do differently?
Try to simplify the code and take it one step at time
BarcodesAssArray := 4016241030924;4016241030924;8710624237479;5900951254741;8710398162939
BarcodeArray := StrSplit(BarcodesAssArray, ";")
MsgBox BarcodeArray(1) BarcodeArray(2) BarcodeArray(3) BarcodeArray(4) BarcodeArray(5)
This will at least get you past the StrSplit statement knowing that you have a valid array
I haven't coded in a while so run at your own risk :)
"Your problem is probably occurring because the keys in your arrays are being treated as numeric. There are limits on the size of numeric keys, depending on whether you are using 32 bit AutoHotkey or 64 bit. The way I would fix this is to cause the keys to be treated as alpha by appending a constant alpha value to the key in the array and stripping it off when displaying, etc the key. This also deals with the case where leading zeros would otherwise be stripped from the numeric keys."
TAC109 - https://www.autohotkey.com/boards/viewtopic.php?p=312566#p312566
BarcodesString := "4016241030924;4016241030924;8710624237479;5900951254741;8710398162939;8710398162939;8710398162939;8710398162939;8710398162939;8710398162939;8710398162939;8710398162939;8710624296933;8710624296872;8710624223885;8710624223885;8711000341001;8711000341001;8711000341001;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260415;8710624260453;"
BarcodesString := RTrim(BarcodesString,";") ; remove trailing ;
BarcodesAssArray := {}
Loop, Parse, BarcodesString, `;
switch BarcodesAssArray.HasKey(A_LoopField . "")
{
case true:BarcodesAssArray[A_LoopField . ""] += 1
case false:BarcodesAssArray[A_LoopField . ""] := 1
}
For key, value in BarcodesAssArray
MsgBox, %key% = %value%
Xtra - https://www.autohotkey.com/boards/viewtopic.php?p=312565#p312565

How to have "input" (or is it context?) dependent hotstrings/hotkeys ?

I want a hotkey or hotstring (whatever is easier), so I can easily convert e.g.
1:5 into [1,2,3,4,5] or
3:7 into [3,4,5,6,7] etc..
I want this to work for all integers...
So I want "multiple variants of the same hotstring" (or, if easier: a hotkey that works somewhat similar: e.g. pressing strg + h and typing 1:3 should produces [1,2,3] )
It should recognize that I typed a number followed by colon followed by another number, and then expand correspondingly..
I looked into the Input function, but it does not seem to be exactly what I want..
I don't need a working solution. Hints & links or keywords for further googling are already helpful..
After typing +h or pressing strg+h, type two numbers to produce the desired outcome:
:*:+h::
^h::
nr := "" ; empty variable's content
end_nr := ""
Input, var, L2 ; Length limit=2
; Input, var, L2 V ; V: Visible
If var is not integer
{
MsgBox, "%var%" is not integer
return
}
first_nr := SubStr(var, 1, 1)
second_nr := SubStr(var, 0)
if (first_nr >= second_nr)
{
MsgBox, "%first_nr%" is greater or equal "%second_nr%"
return
}
Loop
{
nr++ ; increase the number in the variable "nr" by 1 in each iteration
if (nr < first_nr)
continue
If (nr = second_nr)
break
end_nr .= nr . "," ; concatenate the outputs by adding a comma to each one
}
If (first_nr = 0)
MsgBox, "0,%end_nr%%second_nr%"
else
MsgBox, "%end_nr%%second_nr%"
return

Split: A subscript must be between 1 and the size of the array

I have a super simple formula. The problem is that sometimes the data doesn't have a second value, or sometimes the value is blank.
Split ({PO_RECEIVE.VENDOR_LOT_ID}," ")[2]
ID
111 222
123
123 222
I was thinking if I could come up with some logic to figure out whether the string has multiple value's it would solve my problem, but haven't quiet found what I'm looking for:
If {PO_RECEIVE.VENDOR_LOT_ID} = SingleOrBlankString then
{PO_RECEIVE.VENDOR_LOT_ID} else
Split ({PO_RECEIVE.VENDOR_LOT_ID}," ")[2]
Better Example Data:
3011111*42011111111
2711 00291111111
711111//12111111111
/J1111 69111111111
170111
If the string can contain a maximum of two values, separated by a space, then you can check if the string contains a space using the InStr function:
If InStr({PO_RECEIVE.VENDOR_LOT_ID}, " ") > 0 Then
{PO_RECEIVE.VENDOR_LOT_ID}
Else
Split ({PO_RECEIVE.VENDOR_LOT_ID}," ")[2]
If there can be multiple spaces between the parts you can use following formulas to get the values:
Left part:
This function returns the left part of the string until the first space.
If InStr({PO_RECEIVE.VENDOR_LOT_ID}, " ") > 0 Then
Left({PO_RECEIVE.VENDOR_LOT_ID}, InStr({PO_RECEIVE.VENDOR_LOT_ID}, " "))
Right part:
This function returns the right part of the string after the last space.
The InStrRev-function returns the position of the last space because it searches the string backwards.
The Len-function returns the length of the string.
[length] - [position of last space] = [length of the right part]
If InStr({PO_RECEIVE.VENDOR_LOT_ID}, " ") > 0 Then
Right({PO_RECEIVE.VENDOR_LOT_ID}, Len({PO_RECEIVE.VENDOR_LOT_ID}) - InStrRev(testString, " "))

Remove last n characters of string after the dot with Autohotkey

I am using Autohotkey.
I have a string that looks like this S523.WW.E.SIMA. I want to remove the last few characters of the string after the dot (including the dot itself). So, after the removal, the string will look like S523.WW.E.
This may look like a simple question but I just cannot figure out using the available string functions in Autohotkey. How can this be done using Autohotkey? Thank you very much.
Example 1 (last index of)
string := "S523.WW.E.SIMA"
LastDotPos := InStr(string,".",0,0) ; get position of last occurrence of "."
result := SubStr(string,1,LastDotPos-1) ; get substring from start to last dot
MsgBox %result% ; display result
See InStr
See SubStr
Example 2 (StrSplit)
; Split it into the dot-separated parts,
; then join them again excluding the last part
parts := StrSplit(string, ".")
result := ""
Loop % parts.MaxIndex() - 1
{
if(StrLen(result)) {
result .= "."
}
result .= parts[A_Index]
}
Example 3 (RegExMatch)
; Extract everything up until the last dot
RegExMatch(string, "(.*)\.", result)
msgbox % result1
Example 4 (RegExReplace)
; RegExReplace to remove everything, starting with the last dot
result := RegExReplace(string, "\.[^\.]+$", "")