sort a string's characters by using qsort

Post your working scripts, libraries and tools
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

sort a string's characters by using qsort

05 Sep 2019, 04:58

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
}

;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Scripts and Functions”

Who is online

Users browsing this forum: No registered users and 85 guests