BaseToDec / DecToBase

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

BaseToDec / DecToBase

16 Oct 2018, 21:29

- Here are 2 prototype functions for converting between bases.
- I've added in some functionality to help support large bases (i.e. beyond base 36), custom single/multiple character digit strings (instead of 0-9 A-Z), and delimiter-separated numbers (as is typical for sexagesimal i.e. base 60).
- I've provided an example that shows how a DecToBase function can be used to generate string permutations. There are some other functions here:
combinations and permutations (and anagrams) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=34244
- Specifying custom digits for a BaseToDec function can require a case-sensitive lookup table, hence I use a case-sensitive Scripting.Dictionary object.
- Note: for base 16, I would typically use the following characters: 0-9 A-F (10+6=16).
- Note: for base 36, I would typically use the following characters: 0-9 A-Z (10+26=36).
- Note: for base 62, I would typically use the following characters: 0-9 A-Z a-z (10+26+26=62).

Code: Select all

;==================================================
; ;e.g.:

; ;q::
; Loop, 40 ;2 to 41
; 	vBase := A_Index+1
; 	, vOutput .= vBase "`t" JEE_BaseToDec(10, vBase) "`r`n"
; Clipboard := vOutput
; MsgBox, % vOutput
; return

; ;w::
; Loop, 40 ;2 to 41
; 	vBase := A_Index+1
; 	, vOutput .= vBase "`t" JEE_BaseToDec("F0", vBase) "`r`n"
; Clipboard := vOutput
; MsgBox, % vOutput
; return

; ;e::
; oDict := ComObjCreate("Scripting.Dictionary")
; Loop, 70
; 	oDict.Item(A_Index-1) := A_Index - 1
; 	, oDict.Item("" A_Index-1) := A_Index - 1
; 	, oDict.Item(Format("{:02X}", A_Index-1)) := A_Index - 1
; oNum := StrSplit("1:1:1", ":")
; MsgBox, % JEE_BaseToDec(oNum, 60, oDict)
; oNum := StrSplit("01:02:03", ":")
; MsgBox, % JEE_BaseToDec(oNum, 60, oDict)
; oNum := StrSplit("01:00:59", ":")
; MsgBox, % JEE_BaseToDec(oNum, 60, oDict)
; return

;vNum accepts a linear array, treating each item as a digit
;oDict accepts a (case-sensitive) Scripting.Dictionary object as a lookup table
;JEE_Base2Dec
JEE_BaseToDec(vNum, vBase, oDict:="")
{
	local
	static oDefault
	vOutput := 0
	if !IsObject(vNum) && !IsObject(oDict)
	&& (vBase >= 2) && (vBase <= 36)
	{
		vPow := StrLen(vNum)
		Loop, Parse, vNum
		{
			vPow--
			vTemp := Ord(A_LoopField)
			if (vTemp >= 48) && (vTemp <= 57) ;0-9
				vTemp -= 48
			else if (vTemp >= 97) && (vTemp <= 122) ;a-z
				vTemp -= 87
			else if (vTemp >= 65) && (vTemp <= 90) ;A-Z
				vTemp -= 55
			else
				return
			if (vTemp >= vBase)
				return
			vOutput += vTemp * (vBase**vPow)
		}
		return vOutput
	}

	if !IsObject(vNum)
		vNum := StrSplit(vNum)
	if !IsObject(oDefault)
	{
		oDefault := ComObjCreate("Scripting.Dictionary")
		Loop, 10
			oDefault.Item(A_Index-1) := A_Index - 1
			, oDefault.Item("" A_Index-1) := A_Index - 1
		Loop, 26
			oDefault.Item(Chr(64+A_Index)) := A_Index + 9
			, oDefault.Item(Chr(96+A_Index)) := A_Index + 9
	}
	if !IsObject(oDict)
		oDict := oDefault
	vPow := vNum.Length()
	for _, vTemp in vNum
	{
		vPow--
		if !oDict.Exists(vTemp)
			return
		vOutput += oDict.Item(vTemp) * (vBase**vPow)
	}
	return vOutput
}

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

; ;e.g.:

; ;q:: ;binary
; vBase := 2
; vOutput := ""
; Loop, 70
; {
; 	vNum := A_Index-1
; 	, vOutput .= JEE_DecToBase(vNum, vBase) "`r`n"
; }
; Clipboard := vOutput
; MsgBox, % vOutput
; return

; ;w:: ;permutations
; ;vText := "abc"
; vText := "abcde"
; ;vText := "abcdefghij"
; (oArray := StrSplit("_" vText)).RemoveAt(0) ;_,a,b,c,d,e
; vBase := oArray.Length() + 1
; vOutput := ""
; Loop, 70
; {
; 	vNum := A_Index-1
; 	, vTemp := JEE_DecToBase(vNum, vBase, oArray)
; 	if !InStr(vTemp, "_")
; 		vOutput .= vTemp "`r`n"
; }
; Clipboard := vOutput
; MsgBox, % vOutput
; return

;oArray, if used, expects a linear array with keys 0 to 'vBase-1'
JEE_DecToBase(vNum, vBase, oArray:="", vSep:="")
{
	local
	if (vNum = 0)
		return IsObject(oArray) ? oArray.0 : 0
	vTemp := 1
	Loop, 1000
	{
		if (vTemp <= vNum)
			vTemp *= vBase
		else
			break
	}
	vOutput := ""
	Loop, 1000
	{
		vTemp := Floor(vTemp / vBase)
		vDigit := Floor(vNum / vTemp)
		vNum := Mod(vNum, vTemp)
		if (vDigit >= vBase)
			return
		if IsObject(oArray)
		{
			if oArray.HasKey(vDigit)
				vOutput .= oArray[vDigit] vSep
			else
				return
		}
		else if (vDigit <= 9) ;0-9
			vOutput .= vDigit vSep
		else if (vDigit <= 35) ;10-35 (A-Z)
			vOutput .= Chr(55+vDigit) vSep
		else if (vDigit <= 61) ;36-61 (a-z)
			vOutput .= Chr(61+vDigit) vSep
		else
			return
		if (vTemp = 1)
			break
	}
	return StrLen(vSep) ? SubStr(vOutput, 1, -StrLen(vSep)) : vOutput
}

;==================================================
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 (v1)”

Who is online

Users browsing this forum: No registered users and 233 guests