1

I wonder if exist a way to convert a binary value to hexadecimal, in Batch language.

I did a research, but unfortunately due to the discapacities of this language I don't know how to try this, I think is not possible to do this converter?

I will appreciate any kind of information

Mark Skull
  • 39
  • 2
  • 5

3 Answers3

4

One method of converting a string of binary to hex is simply to use a lookup table: 0001=1, 0010=2, etc. Handle the binary string in chunks of four from right to left, converting each segment to base 16 this way. I got the idea from this guy.

Anyway, the :bin2hex subroutine in the following script does that. It chops 4 numbers off the end of the binary string, converts that to hex using a lookup table, and keeps calling itself recursively until there's no binary left. When it's finished recursing, it sets the <var_to_set> argument (%1) to the accumulated string of converted hex values.

@echo off
setlocal

set "bin=110111101010110110111110111011111100101011111110"
call :bin2hex hex %bin%
echo hex: %hex%
goto :EOF

:bin2hex <var_to_set> <bin_value>
set "hextable=0000-0;0001-1;0010-2;0011-3;0100-4;0101-5;0110-6;0111-7;1000-8;1001-9;1010-A;1011-B;1100-C;1101-D;1110-E;1111-F"
:bin2hexloop
setlocal enabledelayedexpansion
if "%~2"=="" (
    endlocal & set "%~1=%~3"
    goto :EOF
)
set "bin=000%~2"
set "oldbin=%~2"
set "bin=%bin:~-4%"
set "hex=!hextable:*%bin:~-4%-=!"
set hex=%hex:;=&rem.%
endlocal & call :bin2hexloop "%~1" "%oldbin:~0,-4%" %hex%%~3
goto :EOF
rojo
  • 24,000
  • 5
  • 55
  • 101
4

This is the same rojo's answer, but slightly modified in order to made it simpler:

@echo off
setlocal

set "bin=110111101010110110111110111011111100101011111110"
call :bin2hex hex=%bin%
echo hex: %hex%
goto :EOF

:bin2hex hexVar=binValue
setlocal EnableDelayedExpansion

for %%a in (0000-0;0001-1;0010-2;0011-3;0100-4;0101-5;0110-6;0111-7;1000-8;1001-9;1010-A;1011-B;1100-C;1101-D;1110-E;1111-F) do (
   for /F "tokens=1,2 delims=-" %%b in ("%%a") do (
      set "hextable[%%b]=%%c"
   )
)

set "hex="
set "bin=000%~2"
:bin2hexloop
   set "hex=!hextable[%bin:~-4%]!%hex%"
   set "bin=%bin:~0,-4%"
if defined bin if "%bin:~3%" neq "" goto bin2hexloop
endlocal & set "%~1=%hex%"
goto :EOF
Aacini
  • 65,180
  • 12
  • 72
  • 108
3

Here is another variation optimized for performance. It uses a FOR /L loop to limit the number of slow GOTO executions. The loop limit of 50 is somewhat arbitrary - it can be changed quite a bit without substantive change to performance.

I suppose a marginally faster implementation could be build by using the fast string length method to define a single loop of exactly the right length, without any need for GOTO. But I don't think it will make a significant difference.

This routine is slightly different in that the binary string is the first argument, and the variable name to be used for the return value is a second optional argument. The routine simply prints the result if no 2nd argument is given.

Also, the routine validates the binary string, printing an error if it is not valid.

Finally, it strips leading 0 digits from the result.

@echo off

:Bin2Hex  binStr  [rtnVar]
setlocal enableDelayedExpansion

if "%~1" equ "" (set "bin=error") else set "bin=00000%~1"
for /f "delims=01" %%A in ("%bin%") do (
  echo Invalid binary value>&2
  exit /b 1
)

for %%A in (
  "0000=0" "0001=1" "0010=2" "0011=3" "0100=4" "0101=5" "0110=6" "0111=7"
  "1000=8" "1001=9" "1010=A" "1011=B" "1100=C" "1101=D" "1110=E" "1111=F"
) do set %%A

set "hex="
:loop
for /l %%N in (1 1 50) do (
  for %%N in (!bin:~-4!) do set "hex=!%%N!!hex!"
  set "bin=!bin:~0,-4!"
  if !bin! equ 0 for %%H in (!hex!) do (
    endlocal
    if "%~2" equ "" (echo %%H) else set "%~2=%%H"
    exit /b 0
  )
)
goto :loop

Here is a table comparing the performance characteristics of my, Aacini's, and rojo's code. The times represent the number of seconds it takes to perform one conversion:

 binary |             |          |
 string |             |          |
 length |   rojo      |  Aacini  |  dbenham 
--------+-------------+----------+-----------
        |             |          |
     8  |   0.03      |   0.01   |   0.01
        |             |          |
   638  |   1.20      |   0.26   |   0.04
        |             |          |
  4000  | ERROR: CALL |   2.06   |   0.30
        | stack limit |          |
        | exceeded    |          |



--------------------------------------------

As requested by rojo, here is a version that uses left shift and processes one bit at a time. It is roughly half as fast as my optimized lookup version:

@echo off

:Bin2Hex  binStr  [rtnVar]
setlocal enableDelayedExpansion

if "%~1" equ "" (set "bin=error") else set "bin=0000%~1"
for /f "delims=01" %%A in ("%bin%") do (
  echo Invalid binary value>&2
  exit /b 1
)

set "hexDigit=0123456789ABCDEF"

set "hex="
:loop
for /l %%N in (1 1 50) do (
  set /a nibble=0
  for /l %%n in (0 1 3) do (
    set /a "nibble+=!bin:~-1!<<%%n"
    set "bin=!bin:~0,-1!"
  )
  for %%n in (!nibble!) do set "hex=!hexDigit:~%%n,1!!hex!"
  if !bin! equ 0 for %%H in (!hex!) do (
    endlocal
    if "%~2" equ "" (echo %%H) else set "%~2=%%H"
    exit /b 0
  )
)
goto :loop
Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • Clever embedding a `for /L` within a `goto` loop for speed optimization. I'm surprised you didn't offer some esoteric bitwise shift solution though. – rojo Dec 20 '14 at 19:34
  • @rojo - I did develop one, but it is not nearly as fast as doing a direct translation with 4 bits at a time. – dbenham Dec 20 '14 at 20:00
  • I'd still be interested in seeing it just to see how it's done. I'd like to understand bitwise shifts better, as they seem like dark sorcery to me. Would you post it as a second answer? – rojo Dec 20 '14 at 20:03
  • 1
    @rono - OK, I've added a left shift solution. Every left shift by 1 multiplies the value by 2. Put another way, x left shift n is the same as x to the nth power. For this solution, x is always 0 or 1 (1 bit) and n ranges between 0 and 3 (4 bits = one nibble = one hex digit) – dbenham Dec 20 '14 at 20:50
  • @dbenham your script works fine, but i need those trainling 0's. It would be terribly kind of you if you could tell me how to leave those 0's in the result and print out \r\n after every 16 bit converted. I could find it out by myself but I have no batch experience and would probably take a lot of time to do it. I would be very thankful for these tweaks. – flautzr Mar 19 '18 at 17:23