Page 1 of 1

sort a string's characters by using qsort

Posted: 05 Sep 2019, 04:58
by jeeswg
I was testing some msvcrt functions, and noticed qsort could be easily used to sort the characters in a string.
One curio is whether qsort allows a 3-parameter function to be specified (even though only 2 parameters would be used).
Another curio is whether RegisterCallback can specify 2 parameters, when the function actually has 3 parameters.

Code: Select all

q:: ;sort a string by using qsort (case sensitive)
vText := "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
vText := StrAlphabetize(vText, "C")
;Clipboard := vText
MsgBox, % vText ;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
return

w:: ;sort a string by using qsort (case insensitive)
vText := "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
vText := StrAlphabetize(vText)
;Clipboard := vText
MsgBox, % vText ;AaBbCcDdeEfFGgHhiIJjkKLlMmNnOoPpQqRrsStTuUVvwWxXYyZz
return

e:: ;shuffle a string by using qsort
vText := "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
vText := StrShuffle(vText)
;Clipboard := vText
MsgBox, % vText
return

r:: ;reverse a string by using _wcsrev/_strrev
vText := "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
vText := StrReverse(vText)
;Clipboard := vText
MsgBox, % vText
return

t:: ;sort an array by using qsort (proof of concept)
oArray := StrSplit("qwertyuiopasdfghjklzxcvbnm")
oArray2 := ArrSort(oArray)
vOutput := ""
for vKey, vValue in oArray2
	vOutput .= vKey " " vValue "`r`n"
;Clipboard := vOutput
MsgBox, % vOutput
return

;==================================================

;StrAlphabetise
StrAlphabetize(vText, vOpt:="")
{
	local
	static vChrSize := A_IsUnicode ? 2 : 1
	static vFuncCS := A_IsUnicode ? "BinCmpShort" : "BinCmpChar"
	static vFuncCI := A_IsUnicode ? "BinCmpShortLower" : "BinCmpCharLower"
	static pFuncCS := RegisterCallback(vFuncCS, "C", 2)
	static pFuncCI := RegisterCallback(vFuncCI, "C", 2)
	pFunc := InStr(vOpt, "C") ? pFuncCS : pFuncCI
	DllCall("msvcrt\qsort", "Ptr",&vText, "UPtr",StrLen(vText), "UPtr",vChrSize, "Ptr",pFunc, "Cdecl")
	return vText
}

StrShuffle(vText, vOpt:="")
{
	local
	static vChrSize := A_IsUnicode ? 2 : 1
	static pFunc := RegisterCallback("BinCmpRandom", "C", 2)
	DllCall("msvcrt\qsort", "Ptr",&vText, "UPtr",StrLen(vText), "UPtr",vChrSize, "Ptr",pFunc, "Cdecl")
	return vText
}

StrReverse(vText)
{
	local
	static vFunc := "msvcrt\" (A_IsUnicode ? "_wcsrev" : "_strrev")
	DllCall(vFunc, "Str",vText, "Cdecl")
	return vText
}

BinCmpChar(vPtr1, vPtr2, vOffset:=0)
{
	local
	vNum1 := NumGet(vPtr1+0, 0, "UChar")
	vNum2 := NumGet(vPtr2+0, 0, "UChar")
	return (vNum1 > vNum2) ? 1 : (vNum1 < vNum2) ? -1 : -vOffset
}

BinCmpShort(vPtr1, vPtr2, vOffset:=0)
{
	local
	vNum1 := NumGet(vPtr1+0, 0, "UShort")
	vNum2 := NumGet(vPtr2+0, 0, "UShort")
	return (vNum1 > vNum2) ? 1 : (vNum1 < vNum2) ? -1 : -vOffset
}

BinCmpCharLower(vPtr1, vPtr2, vOffset:=0)
{
	local
	vNum1 := NumGet(vPtr1+0, 0, "UChar")
	vNum2 := NumGet(vPtr2+0, 0, "UChar")
	vNum1 := Ord(Format("{:L}", Chr(vNum1)))
	vNum2 := Ord(Format("{:L}", Chr(vNum2)))
	return (vNum1 > vNum2) ? 1 : (vNum1 < vNum2) ? -1 : -vOffset
}

BinCmpShortLower(vPtr1, vPtr2, vOffset:=0)
{
	local
	vNum1 := NumGet(vPtr1+0, 0, "UShort")
	vNum2 := NumGet(vPtr2+0, 0, "UShort")
	vNum1 := Ord(Format("{:L}", Chr(vNum1)))
	vNum2 := Ord(Format("{:L}", Chr(vNum2)))
	return (vNum1 > vNum2) ? 1 : (vNum1 < vNum2) ? -1 : -vOffset
}

BinCmpRandom(vPtr1, vPtr2, vOffset:=0)
{
	local
	vNum := Random(0, 1)
	return vNum ? 1 : -1
}

;==================================================

;proof of concept
ArrSort(oArray)
{
	local
	static pFunc := RegisterCallback("ArrSort_Cmp", "C", 2)
	vCount := oArray.Length()
	VarSetCapacity(vData, vCount*8)
	Loop % vCount
		NumPut(A_Index, &vData, A_Index*8-8, "Int64")
	ArrSort_Cmp(1, oArray)
	DllCall("msvcrt\qsort", "Ptr",&vData, "UPtr",vCount, "UPtr",8, "Ptr",pFunc, "Cdecl")
	ArrSort_Cmp(2, 0)
	oArray2 := []
	oArray2.SetCapacity(oArray.Length())
	Loop % vCount
		vNum := NumGet(&vData, A_Index*8-8, "Int64")
		, oArray2.Push(oArray[vNum])
	return oArray2
}

;proof of concept
ArrSort_Cmp(vPtr1, vPtr2, vOffset:=0)
{
	static oArray
	if (vPtr1 = 1)
	{
		oArray := vPtr2
		return
	}
	else if (vPtr1 = 2)
	{
		oArray := ""
		return
	}
	vValue1 := oArray[NumGet(vPtr1+0, 0, "Int64")]
	vValue2 := oArray[NumGet(vPtr2+0, 0, "Int64")]
	return (vValue1 > vValue2) ? 1 : (vValue1 < vValue2) ? -1 : -vOffset
}

;==================================================

Re: sort a string's characters by using qsort

Posted: 18 Oct 2020, 03:54
by Rohwedder
Hallo,
A_AhkVersion: 1.1.33.02 64bit
Error: Call to nonexistent function.
Specifically: Random(0, 1)
---> 111: vNum := Random(0, 1)

Re: sort a string's characters by using qsort

Posted: 18 Oct 2020, 08:39
by boiler
I’m guessing he had a function like the one below in his personal library that was automatically included.

Code: Select all

Random(min, max) {
	Random, r, min, max
	return r
}