Jump to content
Sign in to follow this  
crashdemons

custom itoa,atoi - for *different* numeral systems

Recommended Posts

crashdemons

Now, before you misread the title; I have no intention of creating a way to allow you to change 123 to "123" as this can already be done in AutoIt with one line of code.

No, these functions are my attempt at changing a value like 65535 to something like "1vvv" in Base32Hex and other numeral systems, and also be able to convert strings of the same sort back to a number.

Now, to be perfectly clear, this is not the string "65535" encoded in Base32, this is the value represented in it's character set.

If this is already possible in an easier, more efficient way and natively - I will gladly "feel embarrassed and shuffle off sheepishly," as the powers that be might state. These functions were just a quick and dirty means to an end.

Feel free to expand it, modify it, make it better though. :D

Why did you need this?

I needed this for my YMSG projects; as Yahoo continually uses Base32 and Y64 (custom Base64) integer values in cookies and elsewhere.

What should I not to use this for?

As you can guess, there is no point converting a number to the character set for decimal, as String(65535) would work the same. There is also no point to converting a number to a hexadecimal character set, as Hex(65535) already makes that easy. Although, it can still easily do hexadecimal, just less efficiently.

Additionally, these functions will not save the sign for signed values, they will only convert the absolute value.

These functions also only work for numeral systems with a symbol for the value 0. If you want to use this for a numeral systems with multiple characters per digit, you need to input an 0-based digit array when applicable.

So do you have any examples of it in use?

Yes, I do. Here is converting 65535 to a Base32Hex int and back again.

$Base32Hex = __itoa( 65535 , '0123456789abcdefghjiklmnopqrstuv')
$Decimal = __atoi( $Base32Hex , '0123456789abcdefghjiklmnopqrstuv')
;1vvv and 65535

501 to octal and back again

$Octal = __itoa( 501 , '01234567')
$Decimal = __atoi( $Octal , '01234567')
;765 and 501

65535 to a Y64 int and back again

$Y64 = __itoa( 65535 , 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._')
$Decimal = __atoi( $Y64 , 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._', 1)
;P__ and 65535

297 to binary (01...) and back again

$Binary = __itoa( 297 , '01')
 $Decimal = __atoi( $Binary , '01')
;100101001 and 297

135 to an Ascii85 (alternate link) int and back again

$Ascii85 = __itoa( 135 , '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~')
 $Decimal = __atoi( $Ascii85 , '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~', 1)
;1o and 135

So where is the !@#$ing code?

Right here, and for your benefit I have included some comment blocks in what seems to be a semi-standardized way

; #FUNCTION# ====================================================================================================================
; Name ..........: __itoa
; Description ...: Converts an integer to a string representation of the absolute value in a different number system
; Syntax ........: __itoa($iInteger[,$vCharset='0123456789'[,$fOutputString=True]])
; Parameters ....: $iInteger - Integer value to convert
;   $vCharset - String or 0-based Array containing the digits in the number system to convert to
;   $fOutputString - Determines whether the output is a string or 0-based Digit array.
; Return values .: Success -
;   | Returns a string of digits from the chosen number system, if fOutputString is True
;   | Returns a 0-based Array of digits from the chosen number system, if fOutputString is False
;   Failure - Returns "" and sets @error to:
;   |@error = 1 : Charset too short (2 characters minimum required)
; Author ........: Crash Daemonicus (crashdemons)
; Modified ......:
; Remarks .......: This function assumes the Most-significant digit on the output is always on the left.
;   This function assumes that the character-set given goes from least to greatest in value,
;   | with the first character at value 0.
;   If the value of the input is zero, the first digit of the given character set is output.
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================

Func __itoa($iInteger,$vCharset='0123456789',$fOutputString=True); NOTE: this function assumes the Most-significant char is on the left!
    Local $iCharsetStart=0
    If IsArray($vCharset)=0 Then
        $vCharset=StringSplit($vCharset,'')
        $iCharsetStart=1
    EndIf
    Local $iCharsetLen=UBound($vCharset)
    Local $iCharsetRadix=$iCharSetLen-$iCharsetStart
    If $iCharsetRadix<2 Then Return SetError(1,0,'')
    If $iInteger<0 Then $iInteger=-$iInteger;make iInteger positive, not sure if this is faster than just ABS'ing it.

    Local $sInteger=''
    Local $aInteger[1]=[0]
    Local $iArrayDim=1
    Do
        Local $remainder=Mod($iInteger,$iCharsetRadix)
        $iInteger=Int($iInteger/$iCharsetRadix)
        Local $sDigit=$vCharset[$remainder+$iCharsetStart]

        If $fOutputString Then
            ;prepend digits
            $sInteger=$sDigit&$sInteger
        Else
            ;there's no great way to prepend an array, so lets append and reverse later
            If $iArrayDim>1 Then ReDim $aInteger[$iArrayDim]
            $aInteger[$iArrayDim-1]=$sDigit
            $iArrayDim+=1
        EndIf
    Until $iInteger=0

    If $fOutputString Then
        If StringLen($sInteger)<1 Then $sInteger=$iCharsetStart[$iCharsetStart]
        Return $sInteger
    Else
        _ArrayReverse($aInteger)
        Return $aInteger
    EndIf
EndFunc

; #FUNCTION# ====================================================================================================================
; Name ..........: __atoi
; Description ...: Converts an absolute value in a different number system to an integer
; Syntax ........: __atoi($vInteger,$vCharset[,$iCaseSense=0])
; Parameters ....: $vInteger - The integer made of digits represented by the given character set (String or 0-based Digit Array)
;   $vCharset - The character set of the number system for the given value (String or 0-based Digit Array)
; Return values .: Success - Returns an integer value converted from the given string
;   Failure - Returns 0 and sets @error to:
;   |@error = 1 : Charset too short (2 characters minimum required)
;   |@error = 2 : Character not found in Charset (invalid input string); @extended is set to the ASCII value.
; Author ........: Crash Daemonicus (crashdemons)
; Modified ......:
; Remarks .......: This function assumes the Most-significant digit on the output is always on the left.
;   This function assumes that the character-set given goes from least to greatest in value,
;   | with the first character at value 0.
;   If you want to convert a multi-character-digit system to a number, you MUST input vInteger as an array,
;   | otherwise it is assumed to be single-character-digit number.
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func __atoi($vInteger,$vCharset,$iCaseSense=0); NOTE: this function assumes the Most-significant char is on the left!
    Local $iInteger=0,$iIntegerStart=0,$iCharsetStart=0
    If IsArray($vInteger)=0 Then
        $vInteger=StringSplit($vInteger,'')
        $iIntegerStart=1
    EndIf
    If IsArray($vCharset)=0 Then
        $vCharset=StringSplit($vCharset,'')
        $iCharsetStart=1
    EndIf
    Local $iIntegerLen=UBound($vInteger)
    Local $iCharsetLen=UBound($vCharset)
    Local $iIntegerMax=$iIntegerLen-1
    Local $iCharsetRadix=$iCharSetLen-$iCharsetStart
    If $iCharsetRadix<2 Then Return SetError(1,0,0); array does not have 2 entries from start position

    For $i=$iIntegerStart To $iIntegerMax
        Local $iPower=$iIntegerMax-$i
        Local $cIntChar=$vInteger[$i]
        Local $iCharVal=_ArraySearch($vCharset,$cIntChar,$iCharsetStart,0,$iCaseSense)-$iCharsetStart
        If $iCharVal<0 Then Return SetError(2,Asc($cIntChar),0); would only happen if part of sInt isn't in the Charset
        Local $iValue=$iCharVal*($iCharsetRadix^$iPower)
        $iInteger+=$iValue
    Next
    Return $iInteger
EndFunc

Feel free to strip out the commented-out ConsoleWrite's used in debugging.

Is this useful at all?

It was for me, let me know if it is for you!

Edit: Renamed variable in one of the examples.

Edit: Fixed the "alternate link" not being so alternate

Edited by crashdemons

My Projects - WindowDarken (Darken except the active window) Yahsmosis Chat Client (Discontinued) StarShooter Game (Red alert! All hands to battlestations!) YMSG Protocol Support (Discontinued) Circular Keyboard and OSK example. (aka Iris KB) Target Screensaver Drive Toolbar Thingy Rollup Pro (Minimize-to-Titlebar & More!) 2D Launcher physics example Ascii Screenshot AutoIt3 Quine Example ("Is a Quine" is a Quine.) USB Lock (Another system keydrive - with a toast.)

Share this post


Link to post
Share on other sites
crashdemons

Updated the functions in the first post.

Now you can use numeral systems with multiple characters per digit.

Note: You will need to include Array.au3 now

The vCharset parameter of both functions will accept a 0-based array and the vInteger parameter of __atoi will as well. If you need to convert a multi-character-digit number to an integer you will need to pass both as an array when using __atoi.

If you want to use single-character numeral systems, you can still pass strings to either function as normal.

For instance, here's an example that uses a set of two-character digits for each number in Octal:

Dim $aCharset[8]=['a0','b1','c2','d3','e4','f5','g6','h7']; 2-character octal digits
$aInteger = __itoa(266,$aCharset,False); converted, output as an array of digits
$iInteger = __atoi($aInteger,$aCharset); converted back to a number
;$aInteger is ["e4","b1","c2"] and $iInteger is 266
Edited by crashdemons

My Projects - WindowDarken (Darken except the active window) Yahsmosis Chat Client (Discontinued) StarShooter Game (Red alert! All hands to battlestations!) YMSG Protocol Support (Discontinued) Circular Keyboard and OSK example. (aka Iris KB) Target Screensaver Drive Toolbar Thingy Rollup Pro (Minimize-to-Titlebar & More!) 2D Launcher physics example Ascii Screenshot AutoIt3 Quine Example ("Is a Quine" is a Quine.) USB Lock (Another system keydrive - with a toast.)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.