manipulate string with a batch - windows

I've got a string named "code" and an int named "lenght" which is the lenght of "code"
also int "todo" which has a value of 0,1 or 2.
0 should delete a character at position "lenght".
1 should change the caracter at position "lenght" to a random character.
2 should add a random charachter at position "lenght".
how do i archive this goal?
SET code="%*f0"
set length=0
:loop0
if defined # (
set #=%#:~1%
set /A length += 1
goto loop0
)
SET /A location=%RANDOM% * %lenght% / 32768 + 1
SET /A todo=%RANDOM% * 2 / 32768 + 1
IF %todo% == 0(
)
IF %todo% == 1(
)
IF %todo% == 2(
)

If correctly understood you, then:
#echo off
setlocal enabledelayedexpansion
set "str=%~f0"
set "len=0"
set "buf=%str%"
:loop
if defined buf (set buf=%buf:~1%& set /a "len+=1" & goto:loop)
echo Delete char at %%len%% position^:
set /a "len-=1"
echo !str:~0,%len%!
echo.
echo Change char at %%len%% position for random^:
rem set chars string
set "map=abcdefghijklmnopqrstuvwxyz"
rem convert it to array
set "i=0"
for /l %%i in (0, 1, 25) do (
for /l %%j in (1, 1, 1) do (
set "arr.!i!=!map:~%%i,%%j!" & set /a "i+=1"
)
)
rem random set 0..25
set /a "rnd=0+25*%random%/32768"
echo !str:~0,%len%!!arr.%rnd%!
endlocal
exit /b

Related

Increase amount of numbers for picking randomly

There is a batch file that looks for Pen=n in the list.txt and changes its value (n) randomly from the given row of ten numbers (set "var[pen]=1 2 3 4 5 6 7 8 9 10"). But if there are more than ten numbers say twenty (set "var[pen]=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20") or hundred, it is still picking a number from first ten ones ignoring the rest.
#echo off
setlocal EnableDelayedExpansion
set "file=D:\list.txt"
set "temp=D:\temp.txt"
set "var[pen]=1 2 3 4 5 6 7 8 9 10" &
for /L %%i in (1,10,1%time:~-2%) do set "rand=!random!"
(for /F "usebackq tokens=1,2 delims==" %%a in ("%file%") do (
if defined var[%%a] (
call :getRandomValue var="!var[%%a]!"
echo %%a=!var!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > "%temp%"
move /Y "%temp%" "%file%"
pause > nul && pause > nul
goto :EOF
:getRandomValue value="list"
set /A "rand=!random:~-1!+1"
for /F "tokens=%rand%" %%v in (%2) do set "%1=%%v"
Any help would be appreciated.
edit:
the list.txt contains a list of stuff like pen paper rubber etc. with the corresponding value next to it.
pen=5
pencil=43
paper=0
rubber=22
what the bat file does is just putting random number picking in up from the row of numbers provided. in the following case it would change the value of pen to a random number from 1 to 10. but if I add some extra numbers more than ten it will then just ignore them.
You forgot to specify the origin post of this problem. In such a post, there is not any specification about how the probabilities must be given, but all the 3 examples provided have 10 probable values, so I assumed that all probabilities have 10 values. The fix is add the number of probabilities each value can have:
#echo off
setlocal EnableDelayedExpansion
rem Define the probabilities for new values
set "value[apple]=0 0 0 0 0 0 0 1 1 1" & set "num[apple]=10" & rem 0 (70%) or 1 (30%)
set "value[peach]=0 0 0 0 0 1 2 3 4 5" & set "num[peach]=10" & rem from 0 (50%) to 5 (the rest 50%)
set "value[banana]=54 68 82 96" & set "num[banana]=4" & rem each 25%
rem Randomize
for /L %%i in (1,10,1%time:~-2%) do set "ran=!random!"
(for /F "tokens=1,2 delims==" %%a in (input.ini) do (
if defined value[%%a] (
call :getRandomValue value=%%a
echo %%a=!value!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > output.ini
move /Y output.ini input.ini
goto :EOF
:getRandomValue value=item
set /A "ran=%random%%%num[%2]+1"
for /F "tokens=%ran%" %%v in ("!value[%2]!") do set "%1=%%v"
exit /B
You also forget (again) to provide the real format of the input file, that include [headers]:
[Berries]
Strawberry=1
Blackberry=-13
Blueberry=100
Cherry=6
[Fruits]
apple=0
peach=4
banana=18
orange=-2.5
[Vegetables]
Potato=44
Tomato=2
Onion=0
Garlic=17
EDIT 2022/01/08: New method added as requested in comment
As I already said, you have not specified the rules to define the probable values. I proposed a method that works correctly based on your first example, but then you define values that does not conform with my proposed method (10 possible values, like in your first example). I modified the method and then you invented values that does not conform either: "Why 100 values?" "Because any number above 31 will make the method fail..."
I modified the method (again) so you can define the probabilities via value:percent pairs. Here it is:
#echo off
setlocal EnableDelayedExpansion
rem Define the probabilities for new values as value:percent pairs
set "value[apple]=23:17 68:83" & rem 23 at 17%, 68 at 83%
set "value[peach]=0:50 1:10 2:10 3:10 4:10 5:10" & rem from 0 (50%) to 5 (the rest 50%)
set "value[banana]=54:25 68:25 82:25 96:25" & rem each 25%
rem Randomize
for /L %%i in (1,10,1%time:~-2%) do set "ran=!random!"
(for /F "tokens=1,2 delims==" %%a in (input.ini) do (
if defined value[%%a] (
call :getRandomValue %%a
echo %%a=!value!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > output.ini
move /Y output.ini input.ini
goto :EOF
:getRandomValue item
set /A "ran=%random%%%100+1, val=0"
for %%a in (!value[%1]!) do for /F "tokens=1,2 delims=:" %%x in ("%%a") do (
if %ran% gtr !val! set "value=%%x"
set /A val+=%%y
)
exit /B
What you are aiming to do is to randomly index from a list, which requires you to first determine the number of items in the list.
one method of doing so:
#Echo off
Set "var[pen]=a b c d e f g h i"
Rem enable enviroment for !expanison!
Setlocal EnableDelayedExpansion
Rem Build 'array', splitting string on spaces and incrementing array size count
Set _i=1& Set "item[1]=%var[pen]: =" & Set /A "_i+=1" & Set "item[!_i!]=%"
Rem index randomly from known array size [one indexed]
For /f delims^= %%i in ('Set /A !random! %%!_i! + 1')Do Echo(Item:%%i = !Item[%%i]!
Pause

Compare array of numbers in a batch script

I'm trying to compare a sequence of 9 numbers (separated by ,) using a batch file.
The comparison is always made by the corresponding sequence like:
mPrevious[0] <-> mCurrent[0]
mPrevious[1] <-> mCurrent[1]
I need to know if at least one sequece have changed. In the example bellow, 234 changed to 230 and 146 to 149.
The sketch I have so far is:
setlocal ENABLEDELAYEDEXPANSION
#echo off
set mPrevious=229,234,235,127,58,0,131,133,146
set mCurrent=229,230,235,127,58,0,131,133,149
for /f "tokens=1,2,3,4,5,6,7,8,9 delims=," %%a IN ('echo !mPrevious!') do (
)
The number of entries (currently 9) might change in the future. But for now they are just 9.
I'm not sure what is the proper way to do it inside a batch script.
#echo off
title <nul && title ...\%~nx0
setlocal enabledelayedexpansion
set "_mPrevious=229,234,235,127,58,0,131,133,146"
set "_mCurrents=229,230,235,127,58,0,131,133,149"
echo/!_mPrevious!|find "!_mCurrents!" >nul && (
endlocal & echo\Nothing changed^!! & goto :EOF )
for %%i in (!_mPrevious!)do set /a "_i+=1+0" && call set "_mPrev_!_i!=%%~i"
for %%j in (!_mCurrents!)do set /a "_j+=1+0" && call set "_mCurr_!_j!=%%~j"
if !_i! neq !_j! endlocal & echo\Varyables have different lengths^!! & goto :EOF
for /L %%L in (1 1 !_j!)do if !_mPrev_%%~L! neq !_mCurr_%%~L! echo\!_mPrev_%%~L! updated to: !_mCurr_%%~L!
endlocal && goto :EOF
Outputs:
234 updated to: 230
146 updated to: 149
One simple way to do this only if necessary and only if both variable has same length:
Make a first comparison if the variables are the same, there was a change in the values:
echo/!_mPrevious!|find "!_mCurrents!" >nul && (
endlocal & echo\Nothing changed^!! & goto :EOF )
And a second if they continue with the same length:
if !_i! neq !_j! endlocal & echo\Variables have different lengths^!! & goto :EOF
Obs.: 1. I prefer replace [ ] to one simple _
Obs.: 2. Also, change i+= to _i+=1+0, where no need predefined set command: set i=0
The FOR token delimiters are: <SPACE> <TAB> <NBSP> , ; =
Therefore, you can put it into a FOR loop, but it would fail if the content contained * or ?.
#echo off
====SETLOCAL EnableDelayedExpansion EnableExtensions
set/a"#=cnt=0"
::Define lists
set "mPrevious=229,234,235,127,58,0,131,133,146"
set "mCurrent=229,230,235,127,58,0,131,133,149"
FOR %%P in (!mPrevious!) do (
FOR %%C in (!mCurrent!) do (
if !cnt! equ !#! echo(%%P %%C
set/a"cnt+=1"
)
set/a"cnt=0,#+=1"
)
This is an approach using some self-expanding code:
#echo off
setlocal EnableDelayedExpansion
rem // Define constants here:
set "mPrevious=229,234,235,127,58,0,131,133,146"
set "mCurrents=229,230,235,127,58,0,131,133,149"
rem // Initialise auxiliary variables and indexes:
set "nPrevious=,%mPrevious%" & set /A "i=0"
set "nCurrents=,%mCurrents%" & set /A "j=0"
rem // Convert lists to arrays using self-expanding code:
set "_=%nPrevious:,=" & set /A "i+=1" & set "nPrevious[!i!]=%"
set "_=%nCurrents:,=" & set /A "j+=1" & set "nCurrents[!j!]=%"
rem // Verify availability of arrays:
> nul 2>&1 set nPrevious[ || set /A "i=0"
> nul 2>&1 set nCurrents[ || set /A "j=0"
rem // Determine minimal and maximal count:
if %j% gtr %i% (set /A "k=i, l=j" & set "_=#") else (set /A "k=j, l=i" & set "_=")
rem // Compare corresponding elements:
for /L %%K in (1,1,%k%) do if !nPrevious[%%K]! neq !nCurrents[%%K]! (
echo [%%K]: !nPrevious[%%K]! -^> !nCurrents[%%K]!
)
rem // Return removed or added elements:
set /A "k+=1" & for /L %%K in (!k!,1,%l%) do if defined _ (
echo [%%K]: --- -^> !nCurrents[%%K]!
) else (
echo [%%K]: !nPrevious[%%K]! -^> ---
)
endlocal
Sample output, relying on the data of the question:
[2]: 234 -> 230
[9]: 146 -> 149

How to set BATCH if statement to select random predefined variables?

How do I set my if statement to call on different predefined variables based on user input.
Example 1 is red 2 is orange 3 is blue 4 is random.
If user puts 1 they get red. If they put 2 they get orange. If they put 3 they get blue. If they put 4 they get either red, orange, or blue.
The following script shows one way of doing it, using arrays of colors and a method for doing double expansion on a variable (allowing for array access):
#setlocal enableextensions enabledelayedexpansion
#echo off
set color[1]=red
set color[2]=orange
set color[3]=blue
:loop
set /p inp="Enter a number [1=red, 2=orange, 3=blue, 4=random]: "
if "%inp%"=="4" set /a "inp = %RANDOM% %% 3 + 1"
call set color=%%color[%inp%]%%
if "%color%"=="" goto loop
endlocal && set color=%color%
For a more generalised solution, you can look at the following script, which better handles the prompting for arbitrary colors:
#setlocal enableextensions enabledelayedexpansion
#echo off
rem Clear out all color variables then create array.
set color=junk
for /f "delims==" %%a in ('set color') do set %%a=
set /a "count = 0"
set /a "count = count + 1" && set color[!count!]=red
set /a "count = count + 1" && set color[!count!]=orange
set /a "count = count + 1" && set color[!count!]=blue
set /a "count = count + 1" && set color[!count!]=green
set /a "next = count + 1"
rem Loop until color is valid.
:loop
echo.Choices:
for /l %%a in (1,1,%count%) do (
set value=!color[%%a]!
echo. %%a. !value!
)
echo. %next%. Random choice from above
set /p inp="Enter a number: "
rem set inp=1
rem Special handling, choose random value
if "%inp%"=="%next%" set /a "inp = %RANDOM% %% count + 1"
call set color=%%color[%inp%]%%
if "%color%"=="" goto loop
rem Exit local scope, "leaking" color value.
endlocal && set color=%color%
#ECHO Off
SETLOCAL
SET "choices=1=red 2=blue 3=green 4=random"
SET /p inp="[%choices%]: "
FOR /f %%a IN ('echo %choices: =^&echo %') DO SET /a maxchoice=%%a
IF "%inp%"=="%maxchoice%" SET /a inp=%RANDOM% %% (maxchoice - 1) +1
FOR /f "tokens=1,2" %%a IN ('echo %choices: =^&echo %') DO IF "%%a"=="%inp%" SET "hue=%%b"
ECHO %hue%
GOTO :EOF
Here's my version. All you need to do is follow the bouncing ball setting up choices and ensure that random is the last selection.
I started to write a comment as reply to new paxdiablo's solution, but it becomes too large, so I prefer to write my own solution here with all those points included:
#echo off
setlocal EnableDelayedExpansion
rem Create the color array
set n=0
for %%a in (red orange blue green) do (
set /A n+=1
set color[!n!]=%%a
)
set /A next=n+1
rem Show the available colors menu
echo Choices:
echo/
for /L %%i in (1,1,%n%) do echo %%i. !color[%%i]!
echo %next%. Random choice from above
echo/
rem Loop until color is valid
:loop
set /P "inp=Enter a number: "
if "%inp%" equ "%next%" set /A inp=%random% %% n + 1
set color=!color[%inp%]!
if "%color%" equ "" goto loop
echo/
echo Color: %color%

how to get yesterday's date in a batch file

I know how to get today's date in Windows 7. here is the command that I am using:
%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%
But I want to get yesterday, I do not know how.
If you're limited to just cmd.exe, then the other solutions, despite their size, are probably as good as you'll get. However, modern Windows (such as your Win7) ships with quite a few other tools which can do the job far easier.
Just create a VBScript yester.vbs script as follows:
d = date() - 1
wscript.echo year(d) * 10000 + month(d) * 100 + day(d)
Then you can call it from your cmd script with:
for /f %%a in ('cscript //nologo yester.vbs') do set yesterday=%%a
and the yesterday variable will be created in the form yyyymmdd for you to manipulate however you desire.
Found a script that will work to ensure you get the previous day even if the year or month changes Dos Yesterday Batch.
#echo off
set yyyy=
set $tok=1-3
for /f "tokens=1 delims=.:/-, " %%u in ('date /t') do set $d1=%%u
if "%$d1:~0,1%" GTR "9" set $tok=2-4
for /f "tokens=%$tok% delims=.:/-, " %%u in ('date /t') do (
for /f "skip=1 tokens=2-4 delims=/-,()." %%x in ('echo.^|date') do (
set %%x=%%u
set %%y=%%v
set %%z=%%w
set $d1=
set $tok=))
if "%yyyy%"=="" set yyyy=%yy%
if /I %yyyy% LSS 100 set /A yyyy=2000 + 1%yyyy% - 100
set CurDate=%mm%/%dd%/%yyyy%
set dayCnt=%1
if "%dayCnt%"=="" set dayCnt=1
REM Substract your days here
set /A dd=1%dd% - 100 - %dayCnt%
set /A mm=1%mm% - 100
:CHKDAY
if /I %dd% GTR 0 goto DONE
set /A mm=%mm% - 1
if /I %mm% GTR 0 goto ADJUSTDAY
set /A mm=12
set /A yyyy=%yyyy% - 1
:ADJUSTDAY
if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
REM ** Month 12 falls through
:SET31
set /A dd=31 + %dd%
goto CHKDAY
:SET30
set /A dd=30 + %dd%
goto CHKDAY
:LEAPCHK
set /A tt=%yyyy% %% 4
if not %tt%==0 goto SET28
set /A tt=%yyyy% %% 100
if not %tt%==0 goto SET29
set /A tt=%yyyy% %% 400
if %tt%==0 goto SET29
:SET28
set /A dd=28 + %dd%
goto CHKDAY
:SET29
set /A dd=29 + %dd%
goto CHKDAY
:DONE
if /I %mm% LSS 10 set mm=0%mm%
if /I %dd% LSS 10 set dd=0%dd%
REM Set IIS and AWS date variables
set IISDT=%yyyy:~2,2%%mm%%dd%
set AWSDT=%yyyy%-%mm%-%dd%
#echo off
:: Strip the day of the week from the current date
FOR %%A IN (%Date%) DO SET Today=%%A
:: Parse the date, prefix day and month with an extra leading zero
FOR /F "tokens=1-3 delims=/" %%A IN ("%Today%") DO (
SET Day=0%%A
SET Month=0%%B
SET Year=%%C
)
:: Remove excess leading zeroes
SET Day=%Day:~-2%
SET Month=%Month:~-2%
:: Display the results
SET Day
SET Month
SET Year
:: Convert to Julian date
CALL :JDate %Year% %Month% %Day%
:: Display the result
SET JDate
:: Subtract 1 day
SET /A JPast = JDate - 1
:: Display the result
SET JPast
:: Convert back to "normal" date again
CALL :GDate %JPast%
:: Display the result
::SET GDate=20130121
SET GDate
echo The previous day in form YYYYMMDD is %GDate%
pause
::::::::::::::::::::::::::::::::::::::::::::::::::::::
GOTO:EOF
:JDate
:: Convert date to Julian
:: Arguments : YYYY MM DD
:: Returns : Julian date
::
:: First strip leading zeroes
SET MM=%2
SET DD=%3
IF %MM:~0,1% EQU 0 SET MM=%MM:~1%
IF %DD:~0,1% EQU 0 SET DD=%DD:~1%
::
:: Algorithm based on Fliegel-Van Flandern
:: algorithm from the Astronomical Almanac,
:: provided by Doctor Fenton on the Math Forum
:: (http://mathforum.org/library/drmath/view/51907.html),
:: and converted to batch code by Ron Bakowski.
SET /A Month1 = ( %MM% - 14 ) / 12
SET /A Year1 = %1 + 4800
SET /A JDate = 1461 * ( %Year1% + %Month1% ) / 4 + 367 * ( %MM% - 2 -12 * % Month1% ) / 12 - ( 3 * ( ( %Year1% + %Month1% + 100 ) / 100 ) ) / 4 + %DD% - 32075
SET Month1=
SET Year1=
GOTO:EOF
:GDate
:: Convert Julian date back to "normal" Gregorian date
:: Argument : Julian date
:: Returns : YYYY MM DD
::
:: Algorithm based on Fliegel-Van Flandern
:: algorithm from the Astronomical Almanac,
:: provided by Doctor Fenton on the Math Forum
:: (http://mathforum.org/library/drmath/view/51907.html),
:: and converted to batch code by Ron Bakowski.
::
SET /A P = %1 + 68569
SET /A Q = 4 * %P% / 146097
SET /A R = %P% - ( 146097 * %Q% +3 ) / 4
SET /A S = 4000 * ( %R% + 1 ) / 1461001
SET /A T = %R% - 1461 * %S% / 4 + 31
SET /A U = 80 * %T% / 2447
SET /A V = %U% / 11
SET /A GYear = 100 * ( %Q% - 49 ) + %S% + %V%
SET /A GMonth = %U% + 2 - 12 * %V%
SET /A GDay = %T% - 2447 * %U% / 80
:: Clean up the mess
FOR %%A IN (P Q R S T U V) DO SET %%A=
:: Add leading zeroes
IF 1%GMonth% LSS 20 SET GMonth=0%GMonth%
IF 1%GDay% LSS 20 SET GDay=0%GDay%
:: Return value
:: Here you can define the form that you want
SET GDate=%GYear%%GMonth%%GDay%
GOTO:EOF
Here's a solution that creates the earlierday.vbs file on the fly, uses it and deletes it afterwards.
It stores the result in the NewDate variable
This example calculates 1 day ago, but can easily calculate a date further back by changing the value of the Offset variable.
#echo off
set Offset=1
echo d = date() - WScript.Arguments.Item(0) > earlierday.vbs
echo wscript.echo year(d) * 10000 + month(d) * 100 + day(d) >> earlierday.vbs
for /f %%a in ('cscript //nologo earlierday.vbs %Offset%') do set NewDate=%%a
del earlierday.vbs
echo %NewDate%
pause
You could refine this slightly by using %temp%\earlierday.vbs to create the file in the user's temp folder.
Credits to paxdiablo as this is a simple tweak on his earlier post.
EDIT: Here's something with a loop, close to what I actually need it to do. This will take 14 days off today's date and return that date. Then it will keep going back 7 days at a time until it gets to 35 days day ago.
#echo off
SETLOCAL EnableDelayedExpansion
set BackDaysFrom=14
Set BackDaysTo=35
Set BackDaysStep=7
echo d = date() - WScript.Arguments.Item(0) > earlierday.vbs
echo wscript.echo year(d) * 10000 + month(d) * 100 + day(d) >> earlierday.vbs
for /L %%i in (%BackDaysFrom%, %BackDaysStep%, %BackDaysTo%) do (
for /f %%a in ('cscript //nologo earlierday.vbs %%i') do set NewDate=%%a
echo !NewDate!
)
del earlierday.vbs
pause

How to get the value from a dynamic variable in windows batch file

I am using Microsoft Windows XP [Version 5.1.2600]
Trying to do this.
Trying to create the variable dynamically and then read the value out of that variable in a loop.
#ECHO off
SET SQL1=TEST
SET SQL2=TEST1
SET SQL3=TEST2
SET SQL=SQL
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A number=0
FOR /l %%A IN (1,1,3) DO (
SET /A number = number + 1
echo !number!
echo %SQL%!number!
)
endlocal
Output should be
1
test
2
test2
3
test3
I am getting
C:\temp>c.bat
1
SQL1
2
SQL2
3
SQL3
Please help!
Ugh.
First way (note that instead of your number variable, it uses the loop counter variable %%A):
#ECHO off
SET SQL1=TEST
SET SQL2=TEST1
SET SQL3=TEST2
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A number=0
FOR /l %%A IN (1,1,3) DO (
SET /A number = number + 1
echo !number!
echo !SQL%%A!
)
endlocal
Second way (ugly but it does what you want):
#ECHO off
SET SQL1=TEST
SET SQL2=TEST1
SET SQL3=TEST2
SETLOCAL ENABLEDELAYEDEXPANSION
SET /A number=0
FOR /l %%A IN (1,1,3) DO (
SET /A number = number + 1
echo !number!
for %%i in (!number!) do (echo !SQL%%i!)
)
endlocal

Resources