Convert decimal numbers to base 36 and vice versa

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
miskox
Posts: 556
Joined: 28 Jun 2010 03:46

Convert decimal numbers to base 36 and vice versa

#1 Post by miskox » 02 Jun 2014 06:50

Hi all!

Based on this viewtopic.php?p=34025#p34025 I decided to change the record offset number and record length number with some encoded information (to minimize a chance of finding the number user enters in the 'record offset' field because I also modifed the searching for multiple strings (so more than one record could be matched and it is displayed in a loop).

So I was thinking about base 36: character 0..9 and A..Z (all capital letters, english alphabet).

Conversion between decimal and base 36 works (largest number I can store in the field is 999.999.999 (9 digits):

Code: Select all

@echo off
set num=999999999
if not "%1"=="" set num=%1

set /a dec=%num%
set "base36="
set "map=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for /L %%N in (1,1,6) do call :work1
echo(%num%(10)=%base36%(36)
goto :EOF

:work1
set /a d=dec/36
set /a o=dec - 36 * d
set /a dec=d
call set mapca=%%map:~%o%,1%%
set base36=%mapca%%base36%
goto :EOF


Now I have problems in the process of converting base 36 back to decimal numbers:

I have a long working version but I would like to make it more efficient:

Code: Select all

@echo off
set num=GJDGXR
if not "%1"=="" set num=%1

set remainder1=%num:~0,1%
set remainder2=%num:~1,1%
set remainder3=%num:~2,1%
set remainder4=%num:~3,1%
set remainder5=%num:~4,1%
set remainder6=%num:~5,1%

call :getchar %remainder1% char1
call :getchar %remainder2% char2
call :getchar %remainder3% char3
call :getchar %remainder4% char4
call :getchar %remainder5% char5
call :getchar %remainder6% char6

set /a byte1=36 * 36 * 36 * 36 * 36 * char1
set /a byte2=36 * 36 * 36 * 36 * char2
set /a byte3=36 * 36 * 36 * char3
set /a byte4=36 * 36 * char4
set /a byte5=36 * char5
set /a byte6=char6

set /a numm=byte1+byte2+byte3+byte4+byte5+byte6
echo num=%numm%

goto :EOF

:getchar
if "%1"=="0" set %~2=0
if "%1"=="1" set %~2=1
if "%1"=="2" set %~2=2
if "%1"=="3" set %~2=3
if "%1"=="4" set %~2=4
if "%1"=="5" set %~2=5
if "%1"=="6" set %~2=6
if "%1"=="7" set %~2=7
if "%1"=="8" set %~2=8
if "%1"=="9" set %~2=9
if "%1"=="A" set %~2=10
if "%1"=="B" set %~2=11
if "%1"=="C" set %~2=12
if "%1"=="D" set %~2=13
if "%1"=="E" set %~2=14
if "%1"=="F" set %~2=15
if "%1"=="G" set %~2=16
if "%1"=="H" set %~2=17
if "%1"=="I" set %~2=18
if "%1"=="J" set %~2=19
if "%1"=="K" set %~2=20
if "%1"=="L" set %~2=21
if "%1"=="M" set %~2=22
if "%1"=="N" set %~2=23
if "%1"=="O" set %~2=24
if "%1"=="P" set %~2=25
if "%1"=="Q" set %~2=26
if "%1"=="R" set %~2=27
if "%1"=="S" set %~2=28
if "%1"=="T" set %~2=29
if "%1"=="U" set %~2=30
if "%1"=="V" set %~2=31
if "%1"=="W" set %~2=32
if "%1"=="X" set %~2=33
if "%1"=="Y" set %~2=34
if "%1"=="Z" set %~2=35

GOTO :eof


I wanted to make it short and more efficient but I am stuck:

Code: Select all

@echo off
set num=GJDGXR
if not "%1"=="" set num=%1

set /a base36=%num%
set "dec="
set map0=0
set map1=1
set map2=2
set map3=3
set map4=4
set map5=5
set map6=6
set map7=7
set map8=8
set map9=9
set mapA=10
set mapB=11
set mapC=12
set mapD=13
set mapE=14
set mapF=15
set mapG=16
set mapH=17
set mapI=18
set mapJ=19
set mapK=20
set mapL=21
set mapM=22
set mapN=23
set mapO=24
set mapP=25
set mapQ=26
set mapR=27
set mapS=28
set mapT=29
set mapU=30
set mapV=31
set mapW=32
set mapX=33
set mapY=34
set mapZ=35

REM kalk variables replace the POWER function
set /a kalk0=1
set /a kalk1=36
set /a kalk2=36*36
set /a kalk3=36*36*36
set /a kalk4=36*36*36*36
set /a kalk5=36*36*36*36*36

for /L %%N in (0,1,5) do call :work1 %%N
echo(%num%(36)=%dec%(10)
goto :EOF

:work1
set par=%1
sall set chr=%%base36:~%par%,1%%
call set char=%map%chr%%
echo chr=%char%

set /a dec=dec + %chr% * %kalk%1%
echo(%char%
goto :EOf


I just can't the variable subtition to work dynamically:

Code: Select all

set cnt=0
set value=%kalk%%cnt%


should be

Code: Select all

set value=%kalk0%


I prefer *not* to use delayedexpansion etc.

Any ideas?

Saso

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Convert decimal numbers to base 36 and vice versa

#2 Post by foxidrive » 02 Jun 2014 07:04

You have a typo:

sall set chr=%%base36:~%par%,1%%

Aacini
Expert
Posts: 1886
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Convert decimal numbers to base 36 and vice versa

#3 Post by Aacini » 02 Jun 2014 09:44

EDIT 2: I slightly simplified the base36 to decimal conversion

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "map=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

rem Separate digits in map into array elements
set i=0
for /F "delims=" %%a in ('cmd /U /C echo %map%^| find /V ""') do (
   set /A map[%%a]=i, i+=1
)

echo Enter decimal numbers, zero to end
:loop
   echo/
   set /P "decimal=Enter number:    "

   set "base36="
   for /L %%N in (1,1,6) do (
      set /A digit=decimal%%36, decimal/=36
      for %%d in (!digit!) do set "base36=!map:~%%d,1!!base36!"
   )
   echo In base 36: %base36%

   set decimal=0
   for /L %%N in (0,1,5) do (
      set /A "decimal=decimal*36+map[!base36:~%%N,1!]"
   )
   echo Back in base 10: %decimal%

if %decimal% neq 0 goto loop

EDIT: Version with NO delayed expansion:

Code: Select all

@echo off
setlocal

set "map=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

rem Separate digits in map into array elements
set i=0
for /F "delims=" %%a in ('cmd /U /C echo %map%^| find /V ""') do (
   set /A map[%%a]=i, i+=1
)

echo Enter decimal numbers, zero to end
:loop
   echo/
   set /P "decimal=Enter number:    "

   set "base36="
   for /L %%N in (1,1,6) do call :work1
   echo In base 36: %base36%

   set decimal=0
   for /L %%N in (0,1,5) do call :work2 %%N
   echo Back in base 10: %decimal%

if %decimal% neq 0 goto loop
goto :EOF

:work1
set /A digit=decimal%%36, decimal/=36
call set base36=%%map:~%digit%,1%%%base36%
exit /B

:work2
call set index=%%base36:~%1,1%%
set /A decimal=decimal*36+map[%index%]
exit /B


Antonio

miskox
Posts: 556
Joined: 28 Jun 2010 03:46

Re: Convert decimal numbers to base 36 and vice versa

#4 Post by miskox » 02 Jun 2014 12:02

Aacini: thanks alot. Works perfectly.

Saso

miskox
Posts: 556
Joined: 28 Jun 2010 03:46

Re: Convert decimal numbers to base 36 and vice versa

#5 Post by miskox » 02 Jun 2014 13:38

Aacini: I tried to understand everything but it looks like I am too blond (though I am not). Please explain the following commands:

Why does the command below display each part of the 'map' variable as a separate line (record)?

Code: Select all

set "map=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for /F "delims=" %%a in ('cmd /U /C echo %map%^| find /V ""') do echo %%a


I did some searching (even on MS's site for the SET command) for the explanation of the % arithmetic operation - no luck. What does this command do?

Code: Select all

set /A digit=decimal%%36, decimal/=36


Code: Select all

set /A digit=decimal%%36        ??????
set /A decimal/=36                 this is easy: decimal=decimal/36


Based on Aacini's code it would probably not be too difficult to have a base-n to base-m converter (via base-10 probably) (with auto detect when it should end)

Thanks.
Saso

Aacini
Expert
Posts: 1886
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Convert decimal numbers to base 36 and vice versa

#6 Post by Aacini » 02 Jun 2014 14:47

miskox wrote:Aacini: I tried to understand everything but it looks like I am too blond (though I am not). Please explain the following commands:

Why does the command below display each part of the 'map' variable as a separate line (record)?

Code: Select all

set "map=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for /F "delims=" %%a in ('cmd /U /C echo %map%^| find /V ""') do echo %%a


I borrowed this trick from this post some time ago.

miskox wrote:I did some searching (even on MS's site for the SET command) for the explanation of the % arithmetic operation - no luck. What does this command do?

Thanks.
Saso

Yes, this is the type of things that are assumed to be "common knowledge" so they are not well explained in most sites. It is the modulus (remainder) operator that I think first appeared in the C programming language. It gets the remainder of an integer division.

Antonio

Post Reply