- Also, if I have an array of key names or values, that I want to combine into a list, or perform a sort on, I need to know an unused character for these. Often I might like to use CRLFs, however, I need to confirm that they aren't in use.
- I have been curious as to how the AutoHotkey source code handles such problems, of sorting without having a delimiter available, although I don't yet know the answer.
- Btw what if a string contains literally every Unicode character. I had this problem a few times. [EDIT: In such a situation, a StrUnused function would return 0 characters, indicating that no unused characters were available.]
- It's tempting to write code from scratch, every time a function needs a temporary character.
- However, this often clutters up otherwise simple functions.
- It's also tempting to assume that say Chr(1), Chr(2) and Chr(3) are not in use. However, you may have made that exact same assumption earlier, and so those characters would be unavailable.
- Example of a function that needs unused characters:
proof of concept: Send what you mean - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=40546
- The current approach is rather simple, grab text from all strings/object values, concatenate them, and perform a loop using InStr.
- I would welcome any suggestions for improving the function.
- I had wondered if such a function could be made more efficient via the AutoHotkey source code, e.g. if AutoHotkey knows where an object starts and ends, it could perform binary searches on the area to find unused characters. Perhaps you could specify to create an array with a special option, that collected the data close together in the address space.
- At the most basic level, I was curious if AutoHotkey kept information on the total length of all strings in an array, for use with StrJoin, to then prepare a variable with sufficient capacity to concatenate those strings. Something I also need for my current approach.
- Unfortunately also, there isn't an ObjCount function, which I could potentially use to guess the required capacity.
- Here is a prototype StrUnused function, together with examples showing the use of temporary characters when alphabetising/randomising a string. Thanks for reading.
Code: Select all
;StrUnused prototype: find unused characters for use as delimiters/separators
q:: ;StrUnused prototype function: find unused characters for use as delimiters/separators
;RegEx escape characters:
;12 characters that need escaping in RegEx generally: \.*?+[{|()^$
;4 characters that need escaping in a RegEx character class: ^-]\
;note: best to avoid $ as this has a special meaning in RegEx when used in the replacement text parameter
v1 := "\.*?+[{|()^$" . "^-]\" . "0123456789" . " `t" ;some classic characters to exclude
v2 := "hello world" Chr(1) Chr(2) Chr(3)
o1 := ["a","b","c"]
o2 := {a:"A",b:"B",c:"C"}
vUnused := StrUnused(3,v1,v2,o1,o2)
MsgBox, % StrLen(vUnused)
vOutput := ""
Loop, Parse, vUnused
vOutput .= (A_Index=1?"":" ") Ord(A_LoopField)
MsgBox, % vOutput
MsgBox
MsgBox, % StrUnused("3 O",v1,v2,o1,o2).Length()
MsgBox, % StrUnused("3 T VK",v1,v2,o1,o2)
MsgBox, % StrUnused("3 T",v1,v2,o1,o2)
MsgBox, % StrUnused("3 T K",v1,v2,o1,o2)
return
w:: ;randomise string
vText := "abcde"
vUnused := StrUnused(1, "\.*?+[{|()^$", vText)
vText := RegExReplace(vText, ".", "$0" vUnused)
;MsgBox, % vText
Sort, vText, % "D" vUnused " Random"
vText := StrReplace(vText, vUnused)
MsgBox, % vText
return
e:: ;alphabetise string
;vText := "AutoHotkey"
vText := "America"
vUnused := StrUnused(1, "\.*?+[{|()^$", vText)
vText := RegExReplace(vText, ".", "$0" vUnused)
;MsgBox, % vText
vText2 := vText
Sort, vText, % "D" vUnused " F SortStable"
vText := StrReplace(vText, vUnused)
MsgBox, % vText
;warning: unstable sort does not preserve the order
;e.g. for America: 'Aaceimr' (stable sort) cf. 'aAceimr' (unstable sort)
;hence a custom stable sort function was used above
Sort, vText2, % "D" vUnused
vText2 := StrReplace(vText2, vUnused)
MsgBox, % vText2
return
SortStable(vTextA, vTextB, vOffset) ;for use with AHK's Sort command
{
vRet := (vTextA "") > (vTextB) ? 1 : (vTextA "") < (vTextB) ? -1 : -vOffset
return vRet
}
;==================================================
;vOpt: #, number of characters to return
;vOpt: V, retrieve text from object values (default)
;vOpt: K, retrieve text from object keys
;note: specifying both V and K retrieves text from both keys and values
;vOpt: O, return an object
;vOpt: T, return combined string
StrUnused(vOpt, ByRef v1:="", ByRef v2:="", ByRef v3:="", ByRef v4:="", ByRef v5:="", ByRef v6:="", ByRef v7:="", ByRef v8:="", ByRef v9:="", ByRef v10:="", ByRef v11:="", ByRef v12:="", ByRef v13:="", ByRef v14:="", ByRef v15:="", ByRef v16:="", ByRef v17:="", ByRef v18:="", ByRef v19:="", ByRef v20:="")
{
Loop, Parse, vOpt, % " `t"
{
if RegExMatch(A_LoopField, "^\d+$")
vNum := A_LoopField
if InStr(A_LoopField, "K")
vGetKey := 1
if InStr(A_LoopField, "V")
vGetVal := 1
}
if !vGetKey
vGetVal := 1
if !vNum
return
Loop, 20
{
if !IsObject(v%A_Index%)
{
vText .= v%A_Index%
continue
}
for vKey, vValue in v%A_Index%
{
if vGetVal
vText .= vValue
if vGetKey
vText .= vKey
}
}
if InStr(vOpt, "T")
return vText
vCount := 0
Loop, 65535
if !InStr(vText, Chr(A_Index))
{
vOutput .= Chr(A_Index)
vCount++
if (vCount = vNum)
break
}
if InStr(vOpt, "O")
return StrSplit(vOutput)
return vOutput
}
- [EDIT:] Made the v# parameters ByRef, and made 65535 the maximum character to check for, as beyond that you get a pair of Unicode characters when you use Chr().
- [EDIT:] A StrUnused simple version, as a potential candidate AHK function:
Code: Select all
q:: ;StrUnused simple version
vUnused := StrUnusedSimple(3, Chr(1), Chr(3), Chr(5))
vOutput := ""
Loop, Parse, vUnused
vOutput .= (A_Index=1?"":" ") Ord(A_LoopField)
MsgBox, % vOutput
return
StrUnusedSimple(vNum, oArray*)
{
vText := ""
VarSetCapacity(vText, 1000*oArray.Length()*2)
Loop, % oArray.Length()
vText .= oArray[A_Index]
vCount := 0
Loop, 65535
if !InStr(vText, Chr(A_Index))
{
vOutput .= Chr(A_Index)
vCount++
if (vCount = vNum)
break
}
;return StrSplit(vOutput)
return vOutput
}