Search code examples
stringbatch-filerandom

Get random string element


I'm trying to create a string of 116 random characters, I'm terrible at understanding batch files but I managed to create a random number rand from 0 to 15 to get an element from hex_chars=0123456789ABCDEF

But when I try to get and output an element from a string of characters I constantly encounter problems.

@echo off
setlocal enabledelayedexpansion

REM Define the length of the random hex string
set "hex_length=116"

REM Initialize the hex characters
set "hex_chars=0123456789ABCDEF"

REM Variable to store the random hex string
set "random_hex="

REM Loop until the required length is reached
for /L %%i in (1,1,%hex_length%) do (
    REM Generate a random number between 0 and 15
    set /a "rand=((%random% * %random% + %random% %% 281 * %%i) + %time:~-2%) %% 16"
    echo !rand!

    REM Returns 0 every time
    echo !hex_chars:~%rand%,1! 

    REM Returns 0123456789ABCDEFrand every time
    echo !hex_chars:~!rand!,1! 

    REM Get the hex character from hex_chars based on the random number
    set random_hex=%random_hex%!hex_chars:~%rand%,1!
)

REM Output the random hex string
echo Random Hex (116 chars): !random_hex!

endlocal
pause

I thought to get the hex_string element via for but I didn't figure out how to do it correctly

I tried changing the % and ! and ^ symbols in !hex_chars:~!rand!,1!


Solution

  • Don't worry. The management of variables is one of the most confusing points in Batch files, specially the Delayed Expansion feature. The two key points to remember are these:

    • You can not use %standard% expansion inside a command when the value of the variable changes in the same command, like inside a FOR loop; you must use !delayed! expansion instead. There are a lot of questions/answers in this site about this point; I suggest you to read this answer or this one.

    • The second point is that variable expansions can NOT be nested using the same expansion char (% or !); you can only place a %normal% expansion inside a !delayed! one. For example: echo !hex_chars:~!rand!,1! is wrong. You must use a "trick" to avoid such nesting as explained here or here.

    If we apply the first point to your code, your %random% and %time:~-2% expansions must be !random! and !time:~-2! if you want they change in every iteration. And applying the second point, the final working code is this:

    @echo off
    setlocal enabledelayedexpansion
    
    REM Define the length of the random hex string
    set "hex_length=116"
    
    REM Initialize the hex characters
    set "hex_chars=0123456789ABCDEF"
    
    REM Variable to store the random hex string
    set "random_hex="
    
    REM Loop until the required length is reached
    for /L %%i in (1,1,%hex_length%) do (
    
        REM Generate a random number between 0 and 15
        set /a "rand=((!random! * !random! + !random! %% 281 * %%i) + !time:~-2!) %% 16"
        rem echo !rand!
    
        REM Get the hex character from hex_chars based on the random number
        for %%r in (!rand!) do set "random_hex=!random_hex!!hex_chars:~%%r,1!
    )
    
    REM Output the random hex string
    echo Random Hex (116 chars): %random_hex%
    
    endlocal
    pause