[updated: 2019-07-24]
jeeswg's strings tutorial
- Please make any comments, or any requests/suggestions as to further content.
- Do share any links that you found useful re. strings.
==================================================
> INTRO
- We will introduce the built-in string functions and operators.
- Then we will present some classic string examples.
==================================================
> SUMMARY OF FUNCTIONS/COMMANDS
- Chr/Ord [e.g. Chr(33) is '!', Ord("!") is 33]
- Format [useful for concatenating strings/numbers, and displaying numbers in a particular format][also useful for dec to hex/hex to dec]
- InStr [search for a string, return the position of the nth/nth-to-last occurrence]
- RegExMatch/RegExReplace [search for a string/replace strings using RegEx (regular expressions)]
- Sort [sort strings/numbers based on a delimiter character]
- SplitPath [split path/url to variables]
- StrCompare (AHK v2) [compare 2 strings, return positive/0/negative]
- String (AHK v2) [convert a number/object to a string]
- StringCaseSense [determines whether certain functions/operators do case sensitive/insensitive/locale comparisons]
- StringLower/StringUpper (AHK v1) [lower/upper/title case][note: Format can also change a string's case]
- StrLower/StrUpper (AHK v2) [lower/upper/title case][note: Format can also change a string's case]
- StrLen [get a string's length]
- StrPut/StrGet [convert between encodings e.g. ANSI/UTF-8/UTF-16]
- StrReplace [replace/count strings]
- StrSplit [string to array: split a string based on delimiter strings]
- SubStr [crop a string]
- Trim/LTrim/RTrim [remove leading/trailing characters]
- VarSetCapacity [prepare a string with a certain capacity, speeds up appending to a list][note: AHK automatically increases the size of a string buffer when needed]
- Also (control flow statements):
- Loop Parse, var [parse strings by delimiters]
- Loop Parse, var, CSV [parse strings by delimiters]
- for key, value in StrSplit(...) [parse strings by delimiters]
> SUMMARY OF DEPRECATED FUNCTIONS/COMMANDS
Asc -> Ord
AutoTrim -> [no AHK v2 equivalent]
SetFormat -> Format
StringGetPos -> InStr
StringLeft/StringRight -> SubStr
StringTrimLeft/StringTrimRight -> SubStr
StringLen -> StrLen
StringMid -> SubStr
StringReplace -> StrReplace
StringSplit -> StrSplit
Transform -> [various functions][note: Transform-Deref/Transform-HTML do not have AHK v2 equivalents]
- Note: it's very awkward to convert StringSplit to StrSplit.
- A quick fix is to replace a StringSplit one-liner with a Loop Parse two-liner. See here:
AHK v1 to AHK v2 conversion tips/changes summary - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=37&t=36787
- Note: 'var = value' style continuation sections will not be available in AHK v2.
> ADDITIONAL FUNCTIONALITY DEMONSTRATED IN EXAMPLES
- alphabetise/reverse/shuffle (randomise)
- contains/equals/starts/ends (matches) [e.g. var contains (at least one of) list]
- count [note: StrReplace can count string occurrences]
- repeat
- insert/overwrite
- join
- unused [find unused characters e.g. for use as temporary delimiters]
- between [is a string alphabetically between two other strings]
- min/max [biggest/smallest string in a list]
- get case [e.g. is it lower/upper/title/mixed]
- pad string [add text to start/beginning][see LINKS]
- Caesar cipher [see LINKS]
==================================================
> SUMMARY OF STRING PSEUDO-OPERATORS
- Code comparing the following operators/pseudo-operators in AHK v1:
= != <> < <= > >=
- In general, in AHK v1, it's safer to use if-statements with parentheses.
Code: Select all
;legacy syntax (pseudo-operators) (AHK v1):
if var = LiteralString
if var != LiteralString
if var <> LiteralString
if var < LiteralString
if var <= LiteralString
if var > LiteralString
if var >= LiteralString
if var = %var2%
if var != %var2%
if var <> %var2%
if var < %var2%
if var <= %var2%
if var > %var2%
if var >= %var2%
;expression syntax equivalents (operators) (AHK v1):
if (var = "LiteralText")
if (var != "LiteralText")
if (var <> "LiteralText")
if (var < "LiteralText")
if (var <= "LiteralText")
if (var > "LiteralText")
if (var >= "LiteralText")
if (var = var2)
if (var != var2)
if (var <> var2)
if (var < var2)
if (var <= var2)
if (var > var2)
if (var >= var2)
IfEqual / IfLess / IfGreater - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/IfEqual.htm
- Code demonstrating the following pseudo-operators in AHK v1:
between / contains / in / is
Code: Select all
;pseudo-operators (AHK v1)
;note: AHK v2 does not have a 'between' operator
;these look like operators in AHK v1 but are not operators
between
contains
in
is
;note: the case sensitivity of between/contains/in is determined by StringCaseSense
;==================================================
;BETWEEN
if vNum between -3 and 3 ;AHK v1
if (vNum >= -3) && (vNum <= 3) ;AHK v1/v2
if vNum between %vLBound% and %vUBound% ;AHK v1
if (vNum >= vLBound) && (vNum <= vUBound) ;AHK v1/v2
;NOT BETWEEN
if vNum not between -3 and 3 ;AHK v1
if (vNum < -3) || (vNum > 3) ;AHK v1/v2
if vNum not between %vLBound% and %vUBound% ;AHK v1
if (vNum < vLBound) || (vNum > vUBound) ;AHK v1/v2
;==================================================
;CONTAINS
if var contains abc,def,ghi ;AHK v1
if var contains % "abc,def,ghi" ;AHK v1
;('contains' not yet implemented in AHK v2)
if var contains %vList% ;AHK v1
if var contains % vList ;AHK v1
;('contains' not yet implemented in AHK v2)
;NOT CONTAINS
if var not contains abc,def,ghi ;AHK v1
if var not contains % "abc,def,ghi" ;AHK v1
;('contains' not yet implemented in AHK v2)
if var not contains %vList% ;AHK v1
if var not contains % vList ;AHK v1
;('contains' not yet implemented in AHK v2)
;==================================================
;IN
if var in abc,def,ghi ;AHK v1
if var in % "abc,def,ghi" ;AHK v1
;('in' not yet implemented in AHK v2)
if var in %vList% ;AHK v1
if var in % vList ;AHK v1
;('in' not yet implemented in AHK v2)
;NOT IN
if var not in abc,def,ghi ;AHK v1
if var not in % "abc,def,ghi" ;AHK v1
;('in' not yet implemented in AHK v2)
if var not in %vList% ;AHK v1
if var not in % vList ;AHK v1
;('in' not yet implemented in AHK v2)
;==================================================
;IS
if var is number ;AHK v1
if var is "number" ;AHK v2
if (var is "number") ;AHK v2
if var is %vType% ;AHK v1
if var is % vType ;AHK v1
if var is vType ;AHK v2
if (var is vType) ;AHK v2
;IS NOT
if var is not number ;AHK v1
if !(var is "number") ;AHK v2
if var is not %vType% ;AHK v1
if var is not % vType ;AHK v1
if !(var is "number") ;AHK v2
> SUMMARY OF STRING OPERATORS
- Note: many of these operators apply to other variable types (e.g. integers/floats/objects) and to expressions generally.
~= RegExMatch [equivalent to function but with Haystack and Needle parameters only]
contains (AHK v2) [not implemented]
in (AHK v2) [not implemented]
is (AHK v2) [if var is type][if !(var is type)]
. [concatenate][can usually be omitted]
.= [append]
:= [assign]
[e.g. 'var := expression', note: 'var = value' is deprecated]
= [equals (case insensitive)][note: = for *comparison* not assignment][note: 'var = value', by itself, is assignment in AHK v1]
== [equals (case sensitive)]
!= (AHK v1) [not equals (StringCaseSense)]
!= (AHK v2) [not equals (case insensitive]
!== (AHK v2) [not equals (case sensitive)][not in AHK v1]
<> (AHK v1) [not equals (StringCaseSense)][currently not in AHK v2]
< [less-than (StringCaseSense)]
<= [less-than-or-equal-to (StringCaseSense)]
> [greater-than (StringCaseSense)]
>= [greater-than-or-equal-to (StringCaseSense)]
- For these operators: ?: (ternary operator) && || and not or !, a blank string or a string which looks like zero is considered false.
- See 'BASICS: IF (NON-ZERO) (NON-BLANK)', here:
jeeswg's mathematics tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=64545
==================================================
> GENERAL EXAMPLES
- Note: there may be other/better approaches for some of these tasks.
Code: Select all
;==================================================
;CONTENTS
;ASSIGN
;ASSIGN DIFFERENT CONTENTS TO MULTIPLE VARIABLES
;ASSIGN THE SAME CONTENTS TO MULTIPLE VARIABLES
;RETRIEVE CONTENTS
;CONCATENATE
;APPEND
;PREPEND
;REPEAT A STRING
;INSERT
;OVERWRITE
;MULTILINE TEXT
;COMPARE CASE SENSITIVE / INSENSITIVE
;MIN/MAX STRINGS
;SPECIAL CHARACTERS
;IF VAR (NOT) CONTAINS LIST
;IF VAR (NOT) IN LIST
;IF VAR (NOT) STARTS LIST
;IF VAR (NOT) ENDS LIST
;FIND TEXT IN STRING (FIND A NEEDLE IN A HAYSTACK)
;SEARCH FROM THE NTH-TO-LAST CHARACTER BACKWARDS
;SEARCH FROM THE NTH CHARACTER BACKWARDS
;GET SUBSTRING
;CROP STRING
;SUBSTR WITH 0 AS A PARAMETER
;PAD WITH LEADING ZEROS (STRING WITH EXACTLY N CHARACTERS)
;PAD WITH LEADING ZEROS (STRING WITH MINIMUM N CHARACTERS)
;COUNT OCCURRENCES
;REPLACE TEXT (REPLACE 'BEFORE' TEXT WITH 'AFTER' TEXT)
;SPLIT STRING: GET TEXT BEFORE/AFTER POSITION (NEEDLE)
;SPLIT PATH
;TRIM
;ARRAYS/OBJECTS: GET NTH ITEM (SPLIT STRING)
;ARRAYS/OBJECTS: LOOK UP ITEM
;ARRAYS/OBJECTS: PARSE TWO LISTS
;LOOPS: PARSE TWO LISTS (WITHOUT USING ARRAYS/OBJECTS)
;LOOPS: REPLACE MULTIPLE SPACES WITH SINGLES SPACES
;LOOPS: REMOVE LEADING SPACES FROM LINES/LIST ITEMS
;LOOPS: REMOVE TRAILING SPACES FROM LINES/LIST ITEMS
;LOOPS: PARSE STRING
;LOOPS: SLICE STRING
;LOOPS: SPLIT STRING
;LOOPS: SPLIT STRING (SWAP COLUMNS)
;LOOPS: SPLIT STRING (SWAP COLUMNS) (FURTHER EXAMPLE)
;LOOPS: LIST TO TABLE (BY ROWS)
;LOOPS: LIST TO TABLE (BY COLUMNS)
;CONTINUATION SECTIONS
;SORT: CUSTOM COMPARISON FUNCTIONS
;SORT: CUSTOM COMPARISON FUNCTIONS (UNSTABLE V. STABLE SORT)
;SORT: ALPHABETICAL (UNSTABLE)
;SORT: ALPHABETICAL (STABLE)
;SORT: REVERSE LIST
;SORT: BY NTH COLUMN
;SORT: RECORD COMPARISONS
;SORT STRING: ALPHABETISE
;SORT STRING: REVERSE
;SORT STRING: SHUFFLE (RANDOMISE)
;STRING/NUMERIC: COMPARE NUMERIC AS TEXT
;STRING/NUMERIC: CHECK IF VARIABLE LOOKS LIKE STRING/NUMERIC
;STRING/NUMERIC: CHECK IF VARIABLE IS STRING/NUMERIC
;STRING/NUMERIC: IF VAR IS TYPE
;STRING/NUMERIC: GET CASE
;COMMAND STYLE (=) V. EXPRESSION STYLE (:=)
;SENDINPUT (ESCAPING CHARACTERS)
;==================================================
;ASSIGN
var := "hello world"
var := 0
var := "" ;set variable to a blank string
oldvar := "hello world"
newvar := oldvar
var := "hello world"
MsgBox, % var
;store numbers as strings e.g. to preserve leading zeros
var := 000
MsgBox, % var ;000 (AHK v1), 0 (AHK v2)
var := "000"
MsgBox, % var ;000
;==================================================
;ASSIGN DIFFERENT CONTENTS TO MULTIPLE VARIABLES
var1 := "a", var2 := "b", var3 := "c"
MsgBox, % var1 " " var2 " " var3
;==================================================
;ASSIGN THE SAME CONTENTS TO MULTIPLE VARIABLES
var1 := var2 := var3 := "hello world"
var1 := var2 := var3 := 0
;equivalent to:
var3 := "hello world"
var2 := var3
var1 := var2
;==================================================
;RETRIEVE CONTENTS
var := "hello world"
MsgBox, % var
var1 := "hello world"
var2 := var1
MsgBox, % var2
var1 := "hello world"
varname := "var1"
var2 := %varname%
MsgBox, % var2 ;hello world
varname := "var1"
%varname% := "hello world"
MsgBox, % var1 ;hello world
;==================================================
;CONCATENATE
var1 := "a", var2 := "b", var3 := "c"
var4 := var1 "A" var2 var3 "B" "C"
var4 := var1 . "A" . var2 . var3 . "B" . "C" ;equivalent to line above
MsgBox, % var4
;the style without the dots is called 'auto-concat'
;==================================================
;APPEND
var := "hello"
var .= " world"
MsgBox, % var
var1 := "hello"
var2 := "world"
var1 .= " " var2
MsgBox, % var1
;==================================================
;PREPEND
var := "world"
var := "hello " var
MsgBox, % var
var1 := "world"
var2 := "hello"
var1 := var2 " " var1
MsgBox, % var1
;==================================================
;REPEAT A STRING
;via Loop
var := ""
Loop 10
var .= "hello "
MsgBox, % var
;via a custom function
;StrRept(vText, vNum)
;{
; if (vNum <= 0)
; return ""
; VarSetCapacity(vOutput, StrLen(vText)*vNum*(A_IsUnicode?2:1))
; Loop % vNum
; vOutput .= vText
; return vOutput
;}
;
;var := StrRept("hello ", 10)
;MsgBox, % var
;via Format and StrReplace
MsgBox, % Format("{:5}", "") ;(5 spaces)
MsgBox, % Format("{:05}", 0) ;00000
MsgBox, % StrReplace(Format("{:5}", ""), " ", "a") ;aaaaa
MsgBox, % StrReplace(Format("{:5}", ""), " ", "a_") ;a_a_a_a_a_
vText := "abc ", vNum := 5
MsgBox, % StrReplace(Format("{:" vNum "}", ""), " ", vText)
;via VarSetCapacity and StrReplace
vText := "abc ", vNum := 5
vOutput := ""
VarSetCapacity(vOutput, vNum*(1+!!A_IsUnicode), 1)
vOutput := StrReplace(vOutput, Chr(A_IsUnicode?257:1), vText)
MsgBox, % vOutput
;==================================================
;INSERT
vText := "abcdefghijkl"
vText2 := "ZZZZ"
vPos := 7
vText := SubStr(vText, 1, vPos-1) vText2 SubStr(vText, vPos)
MsgBox, % vText
;==================================================
;OVERWRITE
;warning: this could cause a problem if the new string goes beyond the end of the old string
vText := "abcdefghijkl"
vText2 := "ZZZZ"
vPos := 5
;StrPut(vText2, &vText+(vPos-1), StrLen(vText2), "CP0") ;AHK ANSI versions
;StrPut(vText2, &vText+(vPos-1)*2, StrLen(vText2), "UTF-16") ;AHK Unicode versions
StrPut(vText2, &vText+(vPos-1)*(A_IsUnicode?2:1), StrLen(vText2), A_IsUnicode?"UTF-16":"CP0") ;AHK ANSI or Unicode versions
MsgBox, % vText
;alternatively:
vText := "abcdefghijkl"
vText2 := "ZZZZ"
vPos := 5
vText := SubStr(vText, 1, vPos-1) vText2 SubStr(vText, vPos+StrLen(vText2))
MsgBox, % vText
;==================================================
;MULTILINE TEXT
var := "line 1`r`nline 2`r`nline 3"
var := "line 1" Chr(13) Chr(10) "line 2" Chr(13) Chr(10) "line 3"
MsgBox, % var
;because you can get text like 'nline' above, when spellchecking,
;sometimes I split text up like so:
var := "line 1`r`n" "line 2`r`n" "line 3"
;this is another alternative:
var := "line 1" "`r`n" "line 2" "`r`n" "line 3"
;==================================================
;COMPARE CASE SENSITIVE / INSENSITIVE
var1 := "A"
var2 := "a"
;compare case sensitive
if (var1 == var2)
MsgBox, % "same"
else
MsgBox, % "different"
;compare case insensitive
if (var1 = var2)
MsgBox, % "same"
else
MsgBox, % "different"
;compare case sensitive/insensitive depending on A_StringCaseSense
StringCaseSense, On
if !(var1 <> var2)
MsgBox, % "same"
else
MsgBox, % "different"
StringCaseSense, Off
if !(var1 <> var2)
MsgBox, % "same"
else
MsgBox, % "different"
;AHK v1: compare case sensitive/insensitive depending on A_StringCaseSense
;note: in AHK v2, != is always case insensitive
StringCaseSense, On
if !(var1 != var2)
MsgBox, % "same"
else
MsgBox, % "different"
StringCaseSense, Off
if !(var1 != var2)
MsgBox, % "same"
else
MsgBox, % "different"
;[see StringCaseSense re. On/Off/Locale]
;StringCaseSense - Syntax & Usage | AutoHotkey
;https://autohotkey.com/docs/commands/StringCaseSense.htm
;==================================================
;MIN/MAX STRINGS
oArray := StrSplit("qwe,rty,uio,pas,dfg,hjk,lzx,cvb,nm", ",")
vMin := oArray.1
for _, vValue in oArray
{
if ("" vValue < "" vMin)
vMin := vValue
}
MsgBox, % vMin
oArray := StrSplit("qwe,rty,uio,pas,dfg,hjk,lzx,cvb,nm", ",")
vMax := oArray.1
for _, vValue in oArray
{
if ("" vValue > "" vMax)
vMax := vValue
}
MsgBox, % vMax
;==================================================
;SPECIAL CHARACTERS
var := "``"
var := "`%"
var := "`;" ;needs to be escaped in some circumstances
var := """"
var := "`," ;needs to be escaped in some circumstances
var := "`r" ;carriage return
var := "`n" ;linefeed
var := "`t" ;tab
;e.g. semicolon
;a semicolon preceded by a space/tab,
;marks the start of a comment
var := "a;b" ;doesn't require escaping
MsgBox, % var
var := "a `;b" ;requires escaping
MsgBox, % var
;e.g. comma
;Run, % "control desk.cpl,,2" ;doesn't require escaping
;Run, control desk.cpl`,`,2 ;requires escaping
;see also:
;[#EscapeChar (and explanation of escape sequences)]
;#EscapeChar - Syntax & Usage | AutoHotkey
;https://autohotkey.com/docs/commands/_EscapeChar.htm
;==================================================
;IF VAR (NOT) CONTAINS LIST
;equivalent:
if var contains a,b,c
if InStr(var, "a") || InStr(var, "b") || InStr(var, "c")
if InStr(var, "a") OR InStr(var, "b") OR InStr(var, "c")
;equivalent:
if var not contains % var1 "," var2 "," var3
if !InStr(var, var1) && !InStr(var, var2) && !InStr(var, var3)
if !InStr(var, var1) AND !InStr(var, var2) AND !InStr(var, var3)
;see also:
;['if var (not) in/contains' alternatives]
;Improve InStr or IfInString - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=13&t=31812&sid=0538bf13b8a638cac988c4b268cf11b0
;==================================================
;IF VAR (NOT) IN LIST
;equivalent:
if var in red,yellow,green,blue
if (var = "red") || (var = "yellow") || (var = "green") || (var = "blue")
if (var = "red") OR (var = "yellow") OR (var = "green") OR (var = "blue")
;equivalent:
if var not in % var1 "," var2 "," var3
if !(var = var1) && !(var = var2) && !(var = var3)
if !(var = var1) AND !(var = var2) AND !(var = var3)
;==================================================
;IF VAR (NOT) STARTS LIST
if (SubStr(var, 1, 3) = "red") || (SubStr(var, 1, 6) = "yellow") || (SubStr(var, 1, 5) = "green") || (SubStr(var, 1, 4) = "blue")
if !(SubStr(var, 1, 3) = "red") && !(SubStr(var, 1, 6) = "yellow") && !(SubStr(var, 1, 5) = "green") && !(SubStr(var, 1, 4) = "blue")
;==================================================
;IF VAR (NOT) ENDS LIST
vIsV1 := !!SubStr(1, 0) ;for AHK v1/v2 two-way compatibility
if (SubStr(var, vIsV1-3) = "red") || (SubStr(var, vIsV1-6) = "yellow") || (SubStr(var, vIsV1-5) = "green") || (SubStr(var, vIsV1-4) = "blue")
if !(SubStr(var, vIsV1-3) = "red") && !(SubStr(var, vIsV1-6) = "yellow") && !(SubStr(var, vIsV1-5) = "green") && !(SubStr(var, vIsV1-4) = "blue")
;==================================================
;FIND TEXT IN STRING (FIND A NEEDLE IN A HAYSTACK)
vPos := InStr(vText, vNeedle, vCaseSen, vPos, vOcc)
vPos := InStr(vText, " ") ;find first space
vPos := InStr(vText, " ", 0, 1, 1) ;find first space
vPos := InStr(vText, " ", 0, 1, 2) ;find second space
vPos := InStr(vText, " ", 0, 1, n) ;find nth space
vPos := InStr(vText, " ", 0, 0, 1) ;find last space (AHK v1)
vPos := InStr(vText, " ", 0, 0, 2) ;find second-to-last space (AHK v1)
vPos := InStr(vText, " ", 0, 0, n) ;find nth-to-last space (AHK v1)
vPos := InStr(vText, " ", 0, -1, 1) ;find last space (AHK v2)
vPos := InStr(vText, " ", 0, -1, 2) ;find second-to-last space (AHK v2)
vPos := InStr(vText, " ", 0, -1, n) ;find nth-to-last space (AHK v2)
vIsV1 := InStr(1, 1,, 0)
vPos := InStr(vText, " ", 0, vIsV1-1, 1) ;find last space (two-way compatible)
vPos := InStr(vText, " ", 0, vIsV1-1, 2) ;find second-to-last space (two-way compatible)
vPos := InStr(vText, " ", 0, vIsV1-1, n) ;find nth-to-last space (two-way compatible)
;find string (case sensitive)
vText := "aA"
MsgBox, % vPos := InStr(vText, "A", 1)
MsgBox, % vPos := InStr(vText, "a", 1)
;find string (case insensitive)
vText := "aA"
MsgBox, % vPos := InStr(vText, "A", 0)
MsgBox, % vPos := InStr(vText, "a", 0)
;find string (case insensitive)
vText := "aA"
MsgBox, % vPos := InStr(vText, "A")
MsgBox, % vPos := InStr(vText, "a")
;[see StringCaseSense re. On/Off/Locale]
;StringCaseSense - Syntax & Usage | AutoHotkey
;https://autohotkey.com/docs/commands/StringCaseSense.htm
;==================================================
;SEARCH FROM THE NTH-TO-LAST CHARACTER BACKWARDS
vText := "abcd abcd abcd abcd "
;AHK v1
MsgBox, % InStr(vText, " ", 0, 0) ;20 ;search from the last character backwards
MsgBox, % InStr(vText, " ", 0, -1) ;15 ;search from the 2nd-to-last character backwards
MsgBox, % InStr(vText, " ", 0, -5) ;15 ;search from the 6th-to-last character backwards
MsgBox, % InStr(vText, " ", 0, -6) ;10 ;search from the 7th-to-last character backwards
;MsgBox, % InStr(vText, " ", 0, 1-n) ;search from the nth-to-last character backwards
;AHK v1 (equivalent)
MsgBox, % InStr(vText, " ", 0, 1-1) ;20 ;search from the last character backwards
MsgBox, % InStr(vText, " ", 0, 1-2) ;15 ;search from the 2nd-to-last character backwards
MsgBox, % InStr(vText, " ", 0, 1-6) ;15 ;search from the 6th-to-last character backwards
MsgBox, % InStr(vText, " ", 0, 1-7) ;10 ;search from the 7th-to-last character backwards
;MsgBox, % InStr(vText, " ", 0, 1-n) ;search from the nth-to-last character backwards
;AHK v2
MsgBox, % InStr(vText, " ", 0, -1) ;20 ;search from the last character backwards
MsgBox, % InStr(vText, " ", 0, -2) ;15 ;search from the 2nd-to-last character backwards
MsgBox, % InStr(vText, " ", 0, -6) ;15 ;search from the 6th-to-last character backwards
MsgBox, % InStr(vText, " ", 0, -7) ;10 ;search from the 7th-to-last character backwards
;MsgBox, % InStr(vText, " ", 0, -n) ;search from the nth-to-last character backwards
;AHK v1/v2 two-way compatible
vIsV1 := InStr(1, 1,, 0)
MsgBox, % InStr(vText, " ", 0, vIsV1-1) ;20 ;search from the last character backwards
MsgBox, % InStr(vText, " ", 0, vIsV1-2) ;15 ;search from the 2nd-to-last character backwards
MsgBox, % InStr(vText, " ", 0, vIsV1-6) ;15 ;search from the 6th-to-last character backwards
MsgBox, % InStr(vText, " ", 0, vIsV1-7) ;10 ;search from the 7th-to-last character backwards
;MsgBox, % InStr(vText, " ", 0, vIsV1-n) ;search from the nth-to-last character backwards
;==================================================
;SEARCH FROM THE NTH CHARACTER BACKWARDS
;note: fwds (forwards), bwds (backwards), len (length of the string, in this example: 20 characters)
;vText := "abcd abcd abcd abcd "
; | | |
;fwds: 1 10 20
;bwds v1: -19 -10 0
;bwds v1: [-len+1] [-len+10] [-len+20]
;bwds v2: -20 -11 -1
;bwds v2:[-len-1+1][-len-1+10][-len-1+20]
;to search forwards via the InStr function, you specify the positive 'forwards' index of the character
;to search backwards via the InStr function, you specify the zero/negative 'backwards' index of the character
;each character has both a 'forwards' and a 'backwards' index
;to convert from forwards 'F' to backwards 'B':
;B = - Len + F ;AHK v1
;B = - Len - 1 + F ;AHK v2
;B = - Len - !vIsV1 + F ;AHK v1/v2 two-way compatible
;vIsV1 = 1 if the AHK version is version 1
;vIsV1 = 0 if the AHK version is version 2 or some other version
;!vIsV1, is equivalent to 'not vIsV1'
;!1 = 0
;!0 = 1
;so to search backwards from character n:
;vLen := StrLen(vText)
;vIsV1 := InStr(1, 1,, 0)
;vPos := InStr(vText, vNeedle, 0, -vLen+n) ;AHK v1
;vPos := InStr(vText, vNeedle, 0, -vLen-1+n) ;AHK v2
;vPos := InStr(vText, vNeedle, 0, -vLen-!vIsV1+n) ;AHK v1/v2 two-way compatible
;==================================================
;GET SUBSTRING
vText := SubStr(vText, 1, 1) ;get first character
vText := SubStr(vText, 1, 5) ;get first 5 characters
vText := SubStr(vText, 1, n) ;get first n characters
vText := SubStr(vText, 1, 0) ;get last character (AHK v1)
vText := SubStr(vText, 1, -4) ;get last 5 characters (AHK v1)
vText := SubStr(vText, 1, 1-n) ;get last n characters (AHK v1)
vText := SubStr(vText, 1, 1-1) ;get last character (AHK v1) (alternative presentation)
vText := SubStr(vText, 1, 1-5) ;get last 5 characters (AHK v1) (alternative presentation)
vText := SubStr(vText, 1, 1-n) ;get last 5 characters (AHK v1) (alternative presentation)
vText := SubStr(vText, 1, -1) ;get last character (AHK v2)
vText := SubStr(vText, 1, -5) ;get last 5 characters (AHK v2)
vText := SubStr(vText, 1, -n) ;get last n characters (AHK v2)
vIsV1 := !!SubStr(1, 0)
vText := SubStr(vText, 1, vIsV1-1) ;get last character (two-way compatible)
vText := SubStr(vText, 1, vIsV1-5) ;get last 5 characters (two-way compatible)
vText := SubStr(vText, 1, vIsV1-n) ;get last n characters (two-way compatible)
SubStr(vText, 6, 5) ;get characters 6 to 10 inclusive
SubStr(vText, 6, 10-6+1) ;get characters 6 to 10 inclusive
SubStr(vText, vPos1, vPos2-vPos1+1) ;get characters a to b inclusive
;e.g. split date
vDate := A_Now
vYear := SubStr(vDate, 1, 4)
vMonth := SubStr(vDate, 5, 2)
vDay := SubStr(vDate, 7, 2)
vHour := SubStr(vDate, 9, 2)
vMin := SubStr(vDate, 11, 2)
vSec := SubStr(vDate, 13, 2)
;e.g. split date (via RegEx)
vDate := A_Now
MsgBox, % RegExReplace(vDate, "(....)(..)(..)(..)(..)(..)", "$1 $2 $3 $4 $5 $6")
;e.g. get substring
vText := "aaaaabbbbbcccccddddd"
vIsV1 := !!SubStr(1, 0)
MsgBox, % SubStr(vText, 1, 10) ;first 10 characters
MsgBox, % SubStr(vText, 6, 5) ;2nd lot of 5 characters (chars 6-10)
MsgBox, % SubStr(vText, vIsV1-10) ;last 10 characters
MsgBox, % SubStr(vText, vIsV1-10, 5) ;2nd-to-last lot of 5 characters (first 5 of the last 10 characters)
;e.g. get random substring
vText := "abcdefghijklmnopqrstuvwxyz"
vIsV1 := !!SubStr(1, 0)
Loop 10
{
Random, vNum1, 0, 26
Random, vNum2, 1, 26
;random initial substring
vText1 := SubStr(vText, 1, vNum1)
;random final substring
vText2 := vNum1 ? SubStr(vText, vIsV1-vNum1) : ""
;random substring
vText3 := SubStr(vText, vNum2, vNum1)
MsgBox, % vText1 "`r`n" vText2 "`r`n" vText3
}
;==================================================
;CROP STRING
vText := SubStr(vText, 2) ;remove first character
vText := SubStr(vText, 6) ;remove first 5 characters
vText := SubStr(vText, n+1) ;remove first n characters
vText := SubStr(vText, 1, -1) ;remove last character
vText := SubStr(vText, 1, -5) ;remove last 5 characters
vText := SubStr(vText, 1, -n) ;remove last n characters
vText := SubStr(vText, 2, -1) ;remove first and last characters
;==================================================
;SUBSTR WITH 0 AS A PARAMETER
vText := "abcdefghijklmnopqrstuvwxyz"
MsgBox, % SubStr(vText, 0, 10) ;z (AHK v1), (blank) (AHK v2)
MsgBox, % SubStr(vText, 0, 0) ;(blank)
MsgBox, % SubStr(vText, 0, -10) ;(blank)
MsgBox, % SubStr(vText, 10, 0) ;(blank)
MsgBox, % SubStr(vText, 0, 0) ;(blank)
MsgBox, % SubStr(vText, -10, 0) ;(blank)
;==================================================
;PAD WITH LEADING ZEROS (STRING WITH EXACTLY N CHARACTERS)
;get substring and pad with leading zeros (if necessary)
vNum := 3
vIsV1 := !!SubStr(1, 0)
vText := SubStr("00" vNum, vIsV1-2) ;last 2 characters e.g. 03 ;string will be exactly 2 characters longs
vText := SubStr("0000" vNum, vIsV1-4) ;last 4 characters e.g. 0003 ;string will be exactly 4 characters longs
;==================================================
;PAD WITH LEADING ZEROS (STRING WITH MINIMUM N CHARACTERS)
;ensure at least n characters
vNum := 3
MsgBox, % Format("{:02}", vNum) ;03 ;string will be at least 2 digits long
MsgBox, % Format("{:04}", vNum) ;0003 ;string will be at least 4 digits long
vNum := 300
MsgBox, % Format("{:02}", vNum) ;300 ;string will be at least 2 digits long
MsgBox, % Format("{:04}", vNum) ;0300 ;string will be at least 4 digits long
MsgBox, % Format("{:0" vCount "}", vNum) ;vCount: number of leading zeros ;string will be at least vCount digits long
;==================================================
;COUNT OCCURRENCES
vText := "aaa"
StrReplace(vText, "a", "", vCount)
MsgBox, % vCount ;3
;==================================================
;REPLACE TEXT (REPLACE 'BEFORE' TEXT WITH 'AFTER' TEXT)
;replace (without counting replacements)
vText2 := StrReplace(vText1, " ", "",, 1) ;replace first occurrence
vText2 := StrReplace(vText1, " ", "",, 2) ;replace first 2 occurrences
vText2 := StrReplace(vText1, " ", "",, -1) ;replace all occurrences
vText2 := StrReplace(vText1, " ", "") ;replace all occurrences
;replace and count replacements
vText2 := StrReplace(vText1, " ", "", vCount, 1) ;replace first occurrence
vText2 := StrReplace(vText1, " ", "", vCount, 2) ;replace first 2 occurrences
vText2 := StrReplace(vText1, " ", "", vCount, -1) ;replace all occurrences
;==================================================
;SPLIT STRING: GET TEXT BEFORE/AFTER POSITION (NEEDLE)
;split text into 2 variables, before/after the first tab
vText := "abc`tdef"
vPos := InStr(vText, "`t")
vText1 := SubStr(vText, 1, vPos-1)
vText2 := SubStr(vText, vPos+1)
MsgBox, % vText1 "`r`n" vText2
;split text into 2 variables, before/after the first tab
;also handle the case where there is no tab
vText := "abc`tdef"
if (vPos := InStr(vText, "`t"))
vText1 := SubStr(vText, 1, vPos-1), vText2 := SubStr(vText, vPos+1)
else
vText1 := vText2, vText2 := ""
MsgBox, % vText1 "`r`n" vText2
;split text into 2 variables, before/after the first tab
vText := "abc`tdef`tghi"
oArray := StrSplit(vText, "`t",, 2)
MsgBox, % oArray.1 "`r`n" oArray.2
oArray := ""
;split text into 2 variables, before/after the first tab
;also handle the case where there is no tab
vText := "abc`tdef"
vPos := InStr(vText "`t", "`t")
vText1 := SubStr(vText, 1, vPos-1), vText2 := SubStr(vText, vPos+1)
MsgBox, % vText1 "`r`n" vText2
;get root key/subkey
vKey := "HKEY_CURRENT_USER\Software\Microsoft\Notepad"
if (vPos := InStr(vKey, "\"))
vRootKey := SubStr(vKey, 1, vPos-1), vSubKey := SubStr(vKey, vPos+1)
else
vRootKey := vKey, vSubKey := ""
MsgBox, % vRootKey "`r`n" vSubKey
;get first line
if (vPos := InStr(vText1, "`r"))
vText2 := SubStr(vText1, 1, vPos-1)
else
vText2 := vText1
;get last entry in list in comma-separated list
vText1 := "aaa,bbb,ccc,ddd,eee,fff"
vIsV1 := !!SubStr(1, 0)
vText2 := SubStr(vText1, InStr(vText1, ",", 0, vIsV1-1, 1) + 1)
;==================================================
;SPLIT PATH
;vPath := A_AhkPath
vPath := "C:\Program Files\AutoHotkey\AutoHotkeyU32.exe"
SplitPath, vPath, vName, vDir, vExt, vNameNoExt, vDrive
vList := "Path,Name,Dir,Ext,NameNoExt,Drive"
vOutput := ""
Loop Parse, vList, % ","
{
vOutput .= Format("{:L}", A_LoopField) ": " v%A_LoopField% "`r`n"
if (A_Index = 1)
vOutput .= "`r`n"
}
MsgBox, % vOutput
;==================================================
;TRIM
vText := A_Space A_Space A_Space "hello" A_Space A_Space A_Space
MsgBox, % "[" vText "]`r`n[" LTrim(vText) "]`r`n[" Trim(vText) "]`r`n[" RTrim(vText) "]"
vText := "-_-_hello_-_-"
MsgBox, % "[" vText "]`r`n[" LTrim(vText, "-_") "]`r`n[" Trim(vText, "-_") "]`r`n[" RTrim(vText, "-_") "]"
;==================================================
;ARRAYS/OBJECTS: GET NTH ITEM (SPLIT STRING)
vText := "aaa,bbb,ccc,ddd,eee,fff"
oTemp := StrSplit(vText, ",")
MsgBox, % oTemp[3]
MsgBox, % oTemp.3
MsgBox, % oTemp.Length()
oTemp := ""
vText := "a-b=c_d+e"
oTemp := StrSplit(vText, ["-","=","_","+"])
MsgBox, % oTemp.1 "|" oTemp.2 "|" oTemp.3 "|" oTemp.4 "|" oTemp.5
MsgBox, % oTemp.Length()
oTemp := ""
;==================================================
;ARRAYS/OBJECTS: LOOK UP ITEM
oArray1 := StrSplit("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", ",")
oArray2 := ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
oArray3 := {1:"Jan", 2:"Feb", 3:"Mar", 4:"Apr", 5:"May", 6:"Jun", 7:"Jul", 8:"Aug", 9:"Sep", 10:"Oct", 11:"Nov", 12:"Dec"}
var := 3
MsgBox, % oArray1[var]
MsgBox, % oArray2[3]
MsgBox, % oArray3.3
oArray1 := oArray2 := oArray3 := ""
;==================================================
;ARRAYS/OBJECTS: PARSE TWO LISTS
;e.g. combine columns
vDelim := ","
vList1 := "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
vList2 := "January,February,March,April,May,June,July,August,September,October,November,December"
oTemp1 := StrSplit(vList1, vDelim)
oTemp2 := StrSplit(vList2, vDelim)
vCount1 := oTemp1.Length()
vCount2 := oTemp2.Length()
;vMin := vCount1 < vCount2 ? vCount1 : vCount2
vMin := Min(vCount1, vCount2) ;equivalent to line above
vOutput := ""
Loop % vMin
{
vOutput .= oTemp1[A_Index] "`t" oTemp2[A_Index] "`r`n"
}
MsgBox, % vOutput
;==================================================
;LOOPS: PARSE TWO LISTS (WITHOUT USING ARRAYS/OBJECTS)
;e.g. combine columns
vDelim := ","
vList1 := "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
vList2 := "January,February,March,April,May,June,July,August,September,October,November,December"
vPos1X := vPos2X := 0
StrReplace(vList1, vDelim, "", vCount1), vCount1++
StrReplace(vList2, vDelim, "", vCount2), vCount2++
;vMin := vCount1 < vCount2 ? vCount1 : vCount2
vMin := Min(vCount1, vCount2) ;equivalent to line above
vOutput := ""
Loop % vMin
{
if !(A_Index = vMin)
{
vPos1 := InStr(vList1, vDelim, 0, vPos1X+1)
vPos2 := InStr(vList2, vDelim, 0, vPos2X+1)
vTemp1 := SubStr(vList1, vPos1X+1, vPos1-vPos1X-1)
vTemp2 := SubStr(vList2, vPos2X+1, vPos2-vPos2X-1)
}
else
{
vTemp1 := SubStr(vList1, vPos1X+1)
vTemp2 := SubStr(vList2, vPos2X+1)
}
vOutput .= vTemp1 "`t" vTemp2 "`r`n"
vPos1X := vPos1
vPos2X := vPos2
}
MsgBox, % vOutput
;==================================================
;LOOPS: REPLACE MULTIPLE SPACES WITH SINGLES SPACES
vText := "a" A_Space A_Space A_Space "a"
MsgBox, % vText
while InStr(vText, A_Space A_Space)
vText := StrReplace(vText, A_Space A_Space, " ")
MsgBox, % vText
;via RegEx
vText := "a" A_Space A_Space A_Space "a"
MsgBox, % RegExReplace(vText, " {2,}", " ")
;==================================================
;LOOPS: REMOVE LEADING SPACES FROM LINES/LIST ITEMS
vText := " a`r`n b`r`n c`r`n"
MsgBox, % vText
while (SubStr(vText, 1, 1) = " ")
vText := SubStr(vText, 2)
while InStr(vText, "`n ")
vText := StrReplace(vText, "`n ", "`n")
MsgBox, % vText
vText := " a, b, c,"
MsgBox, % vText
while (SubStr(vText, 1, 1) = " ")
vText := SubStr(vText, 2)
while InStr(vText, ", ")
vText := StrReplace(vText, ", ", ",")
MsgBox, % vText
;==================================================
;LOOPS: REMOVE TRAILING SPACES FROM LINES/LIST ITEMS
vText := "a `r`nb `r`nc `r`n"
MsgBox, % vText
vIsV1 := !!SubStr(1, 0)
while (SubStr(vText, vIsV1-1) = " ")
vText := SubStr(vText, 1, -1)
while InStr(vText, " `r")
vText := StrReplace(vText, " `r", "`r")
MsgBox, % vText
vText := "a ,b ,c ,"
MsgBox, % vText
vIsV1 := !!SubStr(1, 0)
while (SubStr(vText, vIsV1-1) = " ")
vText := SubStr(vText, 1, -1)
while InStr(vText, " ,")
vText := StrReplace(vText, " ,", ",")
MsgBox, % vText
;==================================================
;LOOPS: PARSE STRING
vText := "a,b,c"
Loop Parse, vText, % ","
{
vTemp := A_LoopField
MsgBox, % vTemp
}
;==================================================
;LOOPS: SLICE STRING
vText := "abcdefghijklmnopqrstuvwxyz"
vLen := StrLen(vText)
vLenSlice := 5
Loop % Ceil(vLen / vLenSlice)
{
vTemp := SubStr(vText, (A_Index-1)*vLenSlice+1, vLenSlice)
MsgBox, % vTemp
}
;==================================================
;LOOPS: SPLIT STRING
vText := "a,b,c"
Loop Parse, vText, % ","
{
vText%A_Index% := A_LoopField
}
MsgBox, % vText1 "`r`n" vText2 "`r`n" vText3
;==================================================
;LOOPS: SPLIT STRING (SWAP COLUMNS)
vText := " ;continuation section
(
1 A
2 B
3 C
)"
vOutput := ""
Loop Parse, vText, % "`n", % "`r"
{
oTemp := StrSplit(A_LoopField, "`t")
vOutput .= oTemp.2 "`t" oTemp.1 "`r`n"
}
oTemp := ""
MsgBox, % vOutput
;==================================================
;LOOPS: SPLIT STRING (SWAP COLUMNS) (FURTHER EXAMPLE)
vText := " ;continuation section
(Join`r`n
A B C D E
F G H I J
K L M N O
P Q R S T
U V W X Y
Z
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
)"
vOutput := ""
VarSetCapacity(vOutput, (StrLen(vText)+2)*2)
Loop Parse, vText, % "`n", % "`r"
{
oTemp := StrSplit(A_LoopField, "`t")
vTemp := oTemp.2, oTemp.2 := oTemp.3, oTemp.3 := vTemp
vLine := ""
Loop % oTemp.MaxIndex()
vLine .= ((A_Index=1)?"":"`t") oTemp[A_Index]
vOutput .= RTrim(vLine, "`t") "`r`n"
}
oTemp := ""
;Clipboard := vOutput
MsgBox, % vOutput
;==================================================
;LOOPS: LIST TO TABLE (BY ROWS)
;by rows, e.g.:
;abc
;def
;ghi
;list to table 'by rows' (specify column count)
vText := "abcdefghijklmnopqrstuvwxyz"
vNum := 5 ;column count
vSep := "`t"
oArray := StrSplit(vText)
vOutput := ""
Loop % oArray.Length()
{
vOutput .= oArray[A_Index]
vOutput .= !Mod(A_Index, vNum) ? "`r`n" : vSep
}
MsgBox, % vOutput
;==================================================
;LOOPS: LIST TO TABLE (BY COLUMNS)
;by columns, e.g.:
;adg
;beh
;cfi
;list to table 'by columns' (specify row count)
vText := "abcdefghijklmnopqrstuvwxyz"
vNum := 5 ;row count
vSep := "`t"
oArray := StrSplit(vText)
vOutput := ""
vIndex := 1
Loop % oArray.Length()
{
vOutput .= oArray[vIndex]
vIndex += vNum
if (vIndex > oArray.Length())
{
vIndex := Mod(vIndex, vNum) + 1
vOutput .= "`r`n"
}
else
vOutput .= vSep
}
MsgBox, % vOutput
;==================================================
;CONTINUATION SECTIONS
vText := " ;continuation section
(
a
b
c
)"
MsgBox, % vText
vText := " ;continuation section
(Join`r`n
a
b
c
)"
;MsgBox, % vText
vText := " ;continuation section
(Join,
a
b
c
)"
MsgBox, % vText
vText := " ;continuation section
(
a
b
c
)"
MsgBox, % vText
;LTrim, to allow continuation sections which are indented
;not to have leading whitespace
vText := " ;continuation section
(LTrim
a
b
c
)"
MsgBox, % vText
;==================================================
;SORT: CUSTOM COMPARISON FUNCTIONS
;example from the documentation:
MyVar := "1,2,3,4"
Sort, MyVar, F ReverseDirection D, ; Reverses the list so that it contains 4,3,2,1
ReverseDirection(a1, a2, offset)
{
return offset ; Offset is positive if a2 came after a1 in the original list; negative otherwise.
}
;understanding custom comparison functions:
;if want a1 to be earlier in the new list return a negative number
;if want a2 to be earlier in the new list return a positive number
;if want a1 to be later in the new list return a positive number
;if want a2 to be later in the new list return a negative number
;if offset is negative, a2 was earlier in the original list
;if offset is positive, a1 was earlier in the original list
;to reverse order: return offset
;to maintain order: return -offset
;MORE ON COMPARISON FUNCTIONS (COMPARATORS)
;based on this post:
;Need help to write the good example of using "return" - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=66307&p=285029#p285029
;comparators are the classic unintuitive thing in programming
;firstly, 0 ('false') indicates equality, 1/-1 ('true') indicates inequality
;secondly, re. 1/-1, it's hard to remember which way round it works
;1 indicates the first item is considered bigger
;(and in a sort, bigger items are typically put at the end,
;ascending order: e.g. ABC or 123)
;I remember it as a difference function, similar to AHK's DateDiff:
;cmp(4, 2) -> 4 - 2 -> 2 -> 1
;cmp(2, 4) -> 2 - 4 -> -2 -> -1
;cmp(3, 3) -> 3 - 3 -> 0
;although this analogy fails for strings, unless you convert the string to a number
;AHK CUSTOM COMPARISON FUNCTIONS AND THE OFFSET VALUE
;when the AHK Sort function uses a custom comparison function,
;it passes an offset value to the function,
;if arg1 is earlier in the list than (to the left of) arg2,
;then the offset value is positive
vList := "a,b,c,d,e"
Sort, vList, % "D, F MyCmpReportFunc"
return
MyCmpReportFunc(vText1, vText2, vOffset)
{
MsgBox, % vText1 " " vText2 " " vOffset
}
;==================================================
;SORT: CUSTOM COMPARISON FUNCTIONS (UNSTABLE V. STABLE SORT)
;unstable v. stable sort:
;example from the documentation (unstable sort):
MyVar := "def`nabc`nmno`nFGH`nco-op`ncoop`ncop`ncon`n"
Sort, MyVar, F StringSort
StringSort(a1, a2)
{
return a1 > a2 ? 1 : a1 < a2 ? -1 : 0 ; Sorts alphabetically based on the setting of StringCaseSense.
}
;example from the documentation (edited) (stable sort):
MyVar := "def`nabc`nmno`nFGH`nco-op`ncoop`ncop`ncon`n"
Sort, MyVar, F StringSort
StringSortStable(a1, a2, offset)
{
return a1 > a2 ? 1 : a1 < a2 ? -1 : -offset ; Sorts alphabetically based on the setting of StringCaseSense.
}
;==================================================
;SORT: ALPHABETICAL (UNSTABLE)
vText := "q`nw`ne`nr`nt`ny"
Sort, vText
MsgBox, % vText
vText := "q,w,e,r,t,y"
Sort, vText, D,
MsgBox, % vText
;==================================================
;SORT: ALPHABETICAL (STABLE)
;sort: unstable
;ordinarily sorting by the Sort command is unstable,
;i.e. in a case insensitive sort:
;two items that are regarded as identical may be moved
vText := "A,a,a,a,a"
Loop 5
{
Sort, vText, D,
MsgBox, % vText
}
;sort: stable
vText := "A,a,a,a,a"
Loop 5
{
Sort, vText, D, F JEE_SortCasIns
MsgBox, % vText
}
JEE_SortCasIns(vTextA, vTextB, vOffset) ;for use with AHK's Sort command
{
vSCS := A_StringCaseSense
StringCaseSense, Off
vRet := ("" vTextA) > ("" vTextB) ? 1 : ("" vTextA) < ("" vTextB) ? -1 : -vOffset
StringCaseSense, % vSCS
return vRet
}
;==================================================
;SORT: REVERSE LIST
vText := "a,b,c,d,e"
Sort, vText, D, F JEE_SortReverseList
MsgBox, % vText
JEE_SortReverseList(vTextA, vTextB, vOffset) ;for use with AHK's Sort command
{
return vOffset
}
;==================================================
;SORT: BY NTH COLUMN
vText := " ;continuation section
(
1 q
2 w
3 e
4 r
5 t
6 y
)"
vJeeSortCol := 2
vJeeSortColDelim := "`t"
Sort, vText, F JEE_SortByColSpecifyDelim
MsgBox, % vText
JEE_SortByColSpecifyDelim(vTextA, vTextB, vOffset) ;for use with AHK's Sort command
{
global vJeeSortCol
global vJeeSortColDelim
oTemp := StrSplit(vTextA, vJeeSortColDelim)
vTextAX := oTemp[vJeeSortCol]
oTemp := StrSplit(vTextB, vJeeSortColDelim)
vTextBX := oTemp[vJeeSortCol]
oTemp := ""
vRet := ("" vTextAX) > ("" vTextBX) ? 1 : ("" vTextAX) < ("" vTextBX) ? -1 : -vOffset
return vRet
}
;==================================================
;SORT: RECORD COMPARISONS
vText := "a,b,c,d,e"
;vText := "a,a,a,A,a"
vJeeSortLog := ""
Sort, vText, D, F JEE_SortCasInsLog
MsgBox, % vText
MsgBox, % vJeeSortLog
vJeeSortLog := ""
Sort, vText, D, F JEE_SortCasInsUnstableLog
MsgBox, % vText
MsgBox, % vJeeSortLog
JEE_SortCasInsLog(vTextA, vTextB, vOffset) ;for use with AHK's Sort command
{
global vJeeSortLog
vJeeSortLog .= vTextA "`t" vTextB "`r`n"
vSCS := A_StringCaseSense
StringCaseSense, Off
vRet := ("" vTextA) > ("" vTextB) ? 1 : ("" vTextA) < ("" vTextB) ? -1 : -vOffset
StringCaseSense, % vSCS
return vRet
}
JEE_SortCasInsUnstableLog(vTextA, vTextB, vOffset) ;for use with AHK's Sort command
{
global vJeeSortLog
vJeeSortLog .= vTextA "`t" vTextB "`r`n"
vSCS := A_StringCaseSense
StringCaseSense, Off
vRet := ("" vTextA) > ("" vTextB) ? 1 : ("" vTextA) < ("" vTextB) ? -1 : 0
StringCaseSense, % vSCS
return vRet
}
;==================================================
;SORT STRING: ALPHABETISE
;q:: ;alphabetise string (case insensitive)
vText := "HELLO world"
oArray := {}
Loop Parse, vText
oArray[Ord(Format("{:L}", A_LoopField))] .= A_LoopField
vOutput := ""
VarSetCapacity(vOutput, StrLen(vText)*2)
for _, vValue in oArray
vOutput .= vValue
MsgBox, % vOutput
return
;q:: ;alphabetise string (case sensitive)
vText := "HELLO world"
oArray := {}
Loop Parse, vText
oArray[Ord(A_LoopField)] .= A_LoopField
vOutput := ""
VarSetCapacity(vOutput, StrLen(vText)*2)
for _, vValue in oArray
vOutput .= vValue
MsgBox, % vOutput
return
;note: this could also be done like so:
;determine an unused character, to be a delimiter,
;put the delimiter between each character,
;sort the string,
;remove the delimiter
;==================================================
;SORT STRING: REVERSE
;q:: ;reverse string (via DllCall)
;note: _strrev/_wcsrev overwrite the string
vText := "hello world"
vOutput := vText
MsgBox, % vOutput
vFunc := "msvcrt\" (A_IsUnicode ? "_wcsrev" : "_strrev")
DllCall(vFunc, "Str",vOutput, "CDecl")
MsgBox, % vOutput
return
;q:: ;reverse string (via Loop)
vText := "hello world"
vLen := StrLen(vText)
vOutput := ""
VarSetCapacity(vOutput, vLen*2)
Loop % vLen
vOutput .= SubStr(vText, vLen-A_Index+1, 1)
;vOutput .= SubStr(vText, vLen--, 1) ;could use
MsgBox, % vOutput
return
;==================================================
;SORT STRING: SHUFFLE (RANDOMISE)
;q:: ;shuffle string (randomise string)
vText := "0123456789"
vOutput := ""
VarSetCapacity(vOutput, StrLen(vText)*2)
oArray := StrSplit(vText)
while oArray.Length()
{
Random, vNum, 1, % oArray.Length()
vOutput .= oArray.RemoveAt(vNum)
}
MsgBox, % vOutput
return
;(repeating the text above)
;note: this could also be done like so:
;determine an unused character, to be a delimiter,
;put the delimiter between each character,
;sort the string,
;remove the delimiter
;==================================================
;STRING/NUMERIC: COMPARE NUMERIC AS TEXT
vTextA := 1
vTextB := "01"
MsgBox, % (vTextA = vTextB)
MsgBox, % ("" vTextA = vTextB)
vTextA := 1
vTextB := 0x1
MsgBox, % (vTextA = vTextB)
MsgBox, % ("" vTextA = vTextB)
;==================================================
;STRING/NUMERIC: CHECK IF VARIABLE LOOKS LIKE STRING/NUMERIC
vTextA := 0x1
vTextB := "a"
;note: only works in AHK v1
MsgBox, % !(vTextA + 0 = "") ;1=numeric appearance/0=string appearance
MsgBox, % !(vTextB + 0 = "")
;==================================================
;STRING/NUMERIC: CHECK IF VARIABLE IS STRING/NUMERIC
v1 := 3
v2 := "3"
;(blank)=numeric/30=string
MsgBox, % ObjGetCapacity([v1], 1) ;(blank)
MsgBox, % ObjGetCapacity([v2], 1) ;30
;1=numeric/0=string
MsgBox, % !ObjGetCapacity([v1], 1) ;1
MsgBox, % !ObjGetCapacity([v2], 1) ;0
;0=numeric/1=string
MsgBox, % !!ObjGetCapacity([v1], 1) ;0
MsgBox, % !!ObjGetCapacity([v2], 1) ;1
;see also:
;Determine the difference between a number in a string and a number? - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=32869
;==================================================
;STRING/NUMERIC: IF VAR IS TYPE
;vList := "10,-10,10.0,0xA,UPPER,Title,lower,, ,`t,a1,19990101000000,19991313000000"
vList := "10,-10,+10,--10,++10,10.0,0.0,0.,.0,.,0x,A,xA,0xA,UPPER,Title,lower,, ,`t,A,a,1,Aa,A1,a1,Aa1,19990101000000,19991313000000"
vListType := "integer,float,number,digit,xdigit,alpha,upper,lower,alnum,space,time"
vOutput := ""
Loop Parse, vList, % ","
{
vTemp := A_LoopField
vTemp2 := ""
Loop Parse, vListType, % ","
{
if vTemp is %A_LoopField%
vTemp2 .= A_LoopField ","
}
;vOutput .= "[" vTemp "] " SubStr(vTemp2, 1, -1) "`r`n"
vOutput .= RTrim("[" vTemp "] " SubStr(vTemp2, 1, -1)) "`r`n"
}
;Clipboard := vOutput
MsgBox, % vOutput
;see also:
;If Var is Type - Syntax & Usage | AutoHotkey
;https://autohotkey.com/docs/commands/IfIs.htm
;==================================================
;STRING/NUMERIC: GET CASE
;'if var is upper/lower' can be used to identify a string's case,
;here is some code for a custom 'StrGetCase' function
vList := "autohotkey,Autohotkey,AUTOHOTKEY,AutoHotkey"
vOutput := ""
Loop Parse, vList, % ","
{
vTemp := A_LoopField
vOutput .= StrGetCase(vTemp) "`t" vTemp "`r`n"
}
MsgBox, % vOutput
;note: lower/title/upper/mixed
StrGetCase(ByRef vText)
{
if (vText == Format("{:L}", vText))
return "L"
else if (vText == Format("{:T}", vText))
return "T"
else if (vText == Format("{:U}", vText))
return "U"
else
return "X"
}
;==================================================
;COMMAND STYLE (=) V. EXPRESSION STYLE (:=)
;note: AutoTrim can affect command-style variables
;various examples of command-style code (deprecated)
;v. expression-style code
var =
var := ""
var = a
var := "a"
var = 1
var := 1
var := "1"
var = % 1+1
var := 1+1
var3 = %var1%A%var2%B
var3 := var1 "A" var2 "B"
var3 := var1 . "A" . var2 . "B"
var1 = %var2%
var1 := var2
MsgBox, %var%
MsgBox, % var
MsgBox, %var1% %var2% %var3%
MsgBox, % var1 " " var2 " " var3
MsgBox, %var1%`,%var2%`,%var3%
MsgBox, % var1 "," var2 "," var3
if var contains %vList%
if var contains % vList
if var contains a,b,c
if var contains % "a,b,c"
FileAppend, %vOutput%`r`n, %vPath%
FileAppend, % vOutput "`r`n", % vPath
if A_TimeIdlePhysical > %vDuration%
if (A_TimeIdlePhysical > vDuration)
;append
var1 = %var1%%var2%
var1 .= var2
var1 := var1 var2
var1 := var1 . var2
;prepend
var1 = %var2%%var1%
var1 := var2 var1
var1 := var2 . var1
;no equivalent with command-style variables
var1 := "a", var2 := "b", var3 := "c"
var1 := var2 := var3 := "hello world"
;double deref
varname = var1
var1 = a
var2 = % %varname%
MsgBox, % var2
varname := "var1"
var1 := "a"
var2 := %varname%
MsgBox, % var2
MsgBox, % varname ;single deref: varname -> var1
MsgBox, % %varname% ;double deref: varname -> var1 -> a
;continuation sections
vText := " ;continuation section
(
a
b
c
)"
MsgBox, % vText
;equivalent to: vText := " a`n b`n c"
vText = ;continuation section
(
a
b
c
)
MsgBox, % vText
;equivalent to: vText = a`n b`n c
AutoTrim, Off
vText = ;continuation section
(
%A_Space%a
b
c
)
MsgBox, % vText
;equivalent to: vText = %A_Space%a`n b`n c
;if (in AHK v1, the style without parentheses can sometimes give surprising results)
var := "a"
if var = a
MsgBox, % "y1"
if (var = "a")
MsgBox, % "y2"
var := 1
if var = 1
MsgBox, % "y1"
if (var = 1)
MsgBox, % "y2"
if (var = "1")
MsgBox, % "y3"
var1 := "a"
var2 := "a"
if var1 = %var2%
MsgBox, % "y1"
if (var1 = var2)
MsgBox, % "y2"
if ("a" = "a")
MsgBox, % "y1"
;==================================================
;SENDINPUT (ESCAPING CHARACTERS)
;literal text: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
;command style, Raw on, escaped chars: `"
SendInput, % "{Raw}!""#$%&'()*+,-./:;<=>?@[\]^_``{|}~`n"
;command style, Raw off, escaped chars: `" +^#!{}
SendInput, % "{!}""{#}$%&'()*{+},-./:;<=>?@[\]{^}_``{{}|{}}~`n"
;expression style, Raw on, escaped chars: `%
SendInput, {Raw}!"#$`%&'()*+,-./:;<=>?@[\]^_``{|}~`n
;expression style, Raw off, escaped chars: `% +^#!{}
SendInput, {!}"{#}$`%&'()*{+},-./:;<=>?@[\]{^}_``{{}|{}}~`n
;note: {Text} mode treats `r`n as `n
;==================================================
> FREQUENCY COUNT / REMOVE DUPLICATES
See:
jeeswg's objects tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=29232
These sections:
FREQUENCY COUNT (CASE INSENSITIVE) (SORT)
FREQUENCY COUNT (CASE INSENSITIVE) (MAINTAIN ORDER)
FREQUENCY COUNT (CASE SENSITIVE) (MAINTAIN ORDER/SORT)
REMOVE DUPLICATES (CASE INSENSITIVE) (MAINTAIN ORDER/SORT)
REMOVE DUPLICATES (CASE SENSITIVE) (MAINTAIN ORDER/SORT)
> LINKS (KEY STRING FUNCTIONS/COMMANDS):
InStr() - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/InStr.htm
SubStr() - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/SubStr.htm
StrReplace() / StringReplace - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/StringReplace.htm
StrSplit() / StringSplit - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/StringSplit.htm
StringLower / StringUpper - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/StringLower.htm
StrLen() / StringLen - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/StringLen.htm
Chr() - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/Chr.htm
Ord() - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/Ord.htm
[operators/pseudo-operators]
[if var [not] in/contains MatchList]
If Var in/contains MatchList - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/IfIn.htm
[if var is [not] type]
If Var is Type - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/IfIs.htm
[continuation sections]
Scripts - Definition & Usage | AutoHotkey
https://autohotkey.com/docs/Scripts.htm#continuation
> LINKS (FURTHER STRING FUNCTIONS/COMMANDS):
Alphabetical Command and Function Index | AutoHotkey
https://autohotkey.com/docs/commands/
Format() - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/Format.htm
Loop - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/Loop.htm
Arrays - Definition & Usage | AutoHotkey
https://autohotkey.com/docs/misc/Arrays.htm
RegExMatch() - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/RegExMatch.htm
RegExReplace() - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/RegExReplace.htm
==================================================
> LINKS (PROTOTYPE FUNCTIONS FROM WISH LIST 2.0)
[all from 'PROTOTYPE FUNCTIONS', here:]
Wish List 2.0 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=13&t=36789
Sort function + extra features - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=50431
[FileGetPart/(PathGetPart)]
file get part (SplitPath alternative/short-form/long-form/correct case) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=47709
[StrHatch/StrDelimit][add a string every n characters]
[StrPad][add characters to the start/end of a string]
slice string, pad characters - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=47079
[Combin/Permut]
combinations and permutations (and anagrams) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=34244&p=158871#p158871
==================================================
> LINKS
jeeswg's characters tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=26486
jeeswg's RegEx tutorial (RegExMatch, RegExReplace) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=28031
jeeswg's sort algorithms mini-tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=74&t=64447
jeeswg's mathematics tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=64545
jeeswg's dates tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=65544
jeeswg's objects tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=29232
text/list/table functions - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=27023
string hacks - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=34390
[Caesar cipher]
Change letters on a string - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=48704&p=217168#p217168
six case-insensitive comparison functions - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=83&t=66499
[unexpected behaviour, since AHK v1 stores numbers *and* strings for variables]
Object.Push is eating initial zeros - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=64932&p=278890#p278890
if statement influences floating point number - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=14&t=53498&p=232320#p232320
[combine columns]
How to combine text of two seperate files in a new file - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=26127
[swap columns]
how to change the column A with the column B in Text file? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=27721
Match entire line - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=32602
[choose/case]
Selecting a tab in another program - Page 2 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=32717&p=152641#p152641
AutoHotkey Expression Examples: "" %% () and all that
http://www.daviddeley.com/autohotkey/xprxmp/autohotkey_expression_examples.htm
==================================================
> NEW SECTIONS
Spoiler
==================================================