How to have multiple sums in a variable in batch - batch-file

I am trying to create a matrix this one works below) but is slow as it has to loop every number. So i was wondering if you can have multiple %random% %% 2 without just a "(random number) %2" being printed.
#echo off
color 0a
:a
set /a mat=%random% %% 2
echo |set /p=%mat%
goto a

I found this to be much faster:
#echo off
if not "%1" == "max" start /MAX cmd /c %0 max & exit/b
color 0a
setlocal EnableDelayedExpansion
:a
set "addition="
for /L %%i in (1,1,256) do (
set /a mat=!random! %% 2
set addition=!addition!!mat!
)
echo |set /p=%addition%
goto a
EDIT: I now see that the answer #Stephan links to in the comments is very similar, so credit goes to him too.
EDIT #2:
You might like this one too, has all kind of characters so it looks a bit more "matrixy"
#echo off
if not "%1" == "max" start /MAX cmd /c %0 max & exit/b
color a
setlocal EnableDelayedExpansion
set "CHARS=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789######$$$%%%%%%*** "
echo %CHARS%>x&for %%? in (x) do set /a strlength=%%~z? - 2&del x
:a
call :randomString addition 100 "%chars%" %strlength%
echo |set /p=%addition%
goto a
:randomString
set "length=%2"
set "CHARS=%~3"
if ["%CHARS%"]==[""] set "CHARS=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789######$$$%%%%%%***"
set "strlength=%4"
if [%strlength%]==[] echo %CHARS%>x&for %%? in (x) do set /a strlength=%%~z? - 2&del x
set "line="
for /L %%a in (1 1 %length%) do (
set /a "randnr=!random!%%!strlength!"
for /l %%n in (!randnr! 1 !randnr!) do set "line=!line!!CHARS:~%%n,1!"
)
set %1=%line%
exit /b
For extra effect add 6 spaces to the CHARS variable. Note that I also added a line to start it in full-screen mode.

The method below is the fastest possible way to solve this problem:
#echo off
setlocal EnableDelayedExpansion
rem Prepare the output for one line
set "bin=0101010101"
set "line="
for /L %%i in (1,1,79) do (
set "line=!line!%%bin:~^!random:~-1^!,1%%"
)
for /L %%i in () do call echo %line%

Related

Batch - Decreasing value of a variable in substring is not functioning

I'm trying to reverse "hello" to "olleh". But the output shows "ooooo".
I think !string:~%back%,1! is the problem, because when I use echo to test the value of back is decreasing or not, it works, but it doesn't work in substring, so it always get the last character of the string (-1,1).
#echo off
set string=hello
set temp_string=%string%
set /a string_length=0
:find_length
if defined temp_string (
set temp_string=%temp_string:~1%
set /a string_length+=1
goto :find_length
)
:loop
setlocal enabledelayedexpansion
set /a back=-1
for /l %%a in (1,1,!string_length!) do (
set reverse_string=!string:~%back%,1!!reverse_string!
set /a back-=1
)
echo !reverse_string!
pause >nul
As TripeHound commented, %back% needs to be delayed. What you should do is use the for /L loop value of %%a to in place of %back%. (No sense decrementing a variable manually when one's already being decremented for you as a part of the for /L loop, right?)
for /l %%a in (%string_length%,-1,0) do (
call set "reverse_string=!reverse_string!!string:~%%a,1!"
)
goto loops are not very efficient. If you've got a long string you're going to reverse, there'll be a noticeable pause while you count its length if you goto :label for each character. The fastest way I've found to get the length of a string is based on jeb's answer here:
:length <return_var> <string>
setlocal enabledelayedexpansion
if "%~2"=="" (set ret=0) else set ret=1
set "tmpstr=%~2"
for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if not "!tmpstr:~%%I,1!"=="" (
set /a ret += %%I
set "tmpstr=!tmpstr:~%%I!"
)
)
endlocal & set "%~1=%ret%"
goto :EOF
Put it all together like this:
#echo off
setlocal
set "string=%*"
call :length string_length "%string%"
setlocal enabledelayedexpansion
for /l %%a in (%string_length%,-1,0) do (
set "reverse_string=!reverse_string!!string:~%%a,1!"
)
echo(!reverse_string!
pause >nul
exit /b 0
:length <return_var> <string>
setlocal enabledelayedexpansion
if "%~2"=="" (set ret=0) else set ret=1
set "tmpstr=%~2"
for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if not "!tmpstr:~%%I,1!"=="" (
set /a ret += %%I
set "tmpstr=!tmpstr:~%%I!"
)
)
endlocal & set "%~1=%ret%"
goto :EOF
Example output:
command: test.bat The quick brown fox
result: xof nworb kciuq ehT
The problem is that %back% is being used without delayed expansion, so will always have the value -1. Replacing the end of your code with:
set /a back=-1
set /a count=1
:repeat
if %count% gtr %string_length% goto :report
set reverse_string=!string:~%back%,1!!reverse_string!
set /a back-=1
set /a count+=1
goto :repeat
:report
echo !reverse_string!
Will do the trick.
You cannot just use !back! because you need the contrast of !...! and %...% to have a variable index, so you'll have to go back to an old-fashioned :loop construct so %back% gets updated each time around.
As described at this post:
"To get the value of a substring when the index change inside FOR/IF enclose the substring in double percents and precede the command with call. For example:
for /l %%a in (1,1,!string_length!) do (
call set reverse_string=%%string:~!back!,1%%!reverse_string!
set /a back-=1
)
Another way to achieve previous process is using an additional FOR command to change the delayed expansion of the index by an equivalent replaceable parameter, and then use the delayed expansion for the substring. This method run faster than previous CALL:
for /l %%a in (1,1,!string_length!) do (
for %%b in (!back!) do (
set reverse_string=!string:~%%b,1!!reverse_string!
)
set /a back-=1
)
"
However, it is not efficient to first loop thru the string just to count the characters, and then loop again to reverse they. I think the method below should be the fastest one:
#echo off
setlocal EnableDelayedExpansion
set maxLength=80
set string=hello
set "reverse="
for /L %%i in (1,1,%maxLength%) do (
set "reverse=!string:~0,1!!reverse!"
set "string=!string:~1!"
if not defined string goto break
)
:break
echo %reverse%
Here's another algorithm:
#echo off
call :reverse "The quick brown fox"
echo %output%
pause & exit
:reverse
setlocal enableDelayedExpansion
set string=%~1
set index=0
:loopchar
set char=!string:~%index%,1!
if "!char!"=="" endlocal & set output=%output% & exit /b
set output=!char!!output!
set /a index+=1
goto loopchar
"Tricks":
using %index% inside ! to expand its current value instead of call with %% (#Aacini)
export of !output! from the local scope by reassigning it on the same line as endlocal.

Batch script - Assign variable in FOR-IF

I have a file with this output:
ANS8000I Server command: 'ru FailedReport'
Unnamed[1]
------------
9
Unnamed[1]
------------
110
Unnamed[1]
------------
101
I need to take those numbers, and assign it to three different variables. I made this script, but I can't make it to work... I always got "0" as result.
#echo off
setlocal enableextensions enabledelayedexpansion
set /A counter=0
SET /A failed=0
SET /A completed=0
SET /A total=0
for /F "tokens=1 skip=4" %%a in (C:\Users\Desktop\Aux.txt) do (
if "%counter%" EQU 5 (set /A failed=%%a)
if "%counter%" EQU 9 (set /A completed=%%a)
if "%counter%" EQU 13 (set /A total=%%a)
set /A counter+=1
)
echo "Failed: " %failed% >> C:\Users\Desktop\Result.txt
echo "Completed: " %completed% >> C:\Users\Desktop\Result.txt
echo "Total: " %total% >> C:\Users\Desktop\Result.txt
Could anyone help me with this? I tried a lot of combinations (variables with !, %, %%), but I still got the same result.
Thanks!!!
#ECHO OFF
setlocal enableextensions enabledelayedexpansion
set /A counter=0
SET /A failed=0
SET /A completed=0
SET /A total=0
for /F "tokens=1" %%a in (q24152955.txt) do (
ECHO !counter! %%a
if !counter! EQU 3 (set /A failed=%%a)
if !counter! EQU 9 (set /A completed=%%a)
if !counter! EQU 6 (set /A total=%%a)
set /A counter+=1
)
echo "Failed: " %failed%
echo "Completed: " %completed%
echo "Total: " %total%
GOTO :eof
I used a file named q24152955.txt containing your data for my testing.
In delayedexpansion mode, %var% refers to the original value of var - before the loop began execution and !var! is the dynamic value - as it changes.
"something" is never going to be equal to something because the quotes are significant. Quoted values are often used in this context in case the value itself is empty or contains special characters (especially spaces) - "" is a non-empty string.
for /f ignores empty lines. I've included a superfluous echo command to show which lines the for processes. Note that the value of counter is thus the sequential number of non-empty lines in the file, not the actual line number. Note also that a line containing just one (or more) spaces is not an empty line!
#ECHO off&cls
setlocal enabledelayedexpansion
set "$count=1"
for /f "delims=" %%a in (C:\Users\Desktop\Aux.txt) do (
if !$count!==4 set failed=%%a
if !$count!==7 set completed=%%a
if !$count!==10 set total=%%a
set /a $count+=1
)
(echo Failed : %failed: =%
echo Completed : %completed: =%
echo Total : %total: =%)> C:\Users\Desktop\Result.txt

Coping with for loop batch file issues when splitting a text file

Good Afternoon!
Long time reader, first time poster! I have been having a lovely time trying to modify a working batch file to account for variability. The situation is that I have a variable-size text document that normally would be able to be split into sections of 252 lines. The code below worked like a champ:
#echo off & setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: batchsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set /A Split=%Full%/252
for /L %%G in (1,1,%Split%) do type nul > "%name%_%%G%.new"
set X=1
set N=1
set Q=1
set limit = 252
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
set /A Q+=1
echo.%%k>> "%name%_!X!%.new"
if !Q! gtr 252 (
set /A X+=1
set /A Q=1
) else if !N! gtr Full (goto theend
)
)
:theend
echo split into %split% files with 252 lines each
rem pause
However, there were some changes to the formatting of the text, and now instead of four pages of 63 lines per split file, it can be completely variable. The only constant is this final line, which precedes the remaining space for a 63 line page:
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
Note that there is a single space in front of it, as well as multiple spaces, a colon, and underscore characters. Being the meathead that I am, I thought I could insert an if-then statement into the for loop to trigger the batch to split to the next page. However, I could be further from that right now. This is the code I have been smashing my head with:
rem #echo off & setlocal EnableDelayedExpansion
setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: textsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set Name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set stopvar= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
set Split=1
echo %stopvar%
set X=1
type nul > "%name%_!X!%.new"
set N=1
set Q=1
set S=0
set L=63
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
echo %N%
set /A Q+=1
echo %Q%
echo.%%k>> "%name%_!X!%.new"
if ["%%k%" == "!stopvar!"] (
set /A S+=1
)
if !Q! gtr !L! (
if !S! == 1 (
set /A X+=1
set /A Q=1
type nul > "%name%_!X!%.new"
set /A Split+=1
set S=0
)
else set /A L+=63
else if !N! gtr Full goto theend
)
:theend
echo Split into %split% files!
pause
The premise is that every 63 lines, the stop variable (S) is checked. If it is off (0) then the batch will continue to write for another 63 lines (one page). If the stopvar matches the line that is being read by the for loop, S becomes 1. When the program checks again, it will create a new file and begin writing to that new file. Right now, based on turning off #echo off the hangup is at the for loop. See below:
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rrtextsplit texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rem #echo off & setlocal Enabl
eDelayedExpansion
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>setlocal EnableDelayedExpansio
n
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not defined param (
echo.
echo. Usage: rrtextsplit [device:][pathname]filename
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not exist "texttest.txt" (
echo.
echo. File "texttest.txt" not found
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for %j in ("texttest.txt") do
(
set Name=%~dpnj
set ext=%~xj
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>(
set Name=C:\Users\theangryasiancp\Desktop\TEXT_Split_Test\texttest
set ext=.txt
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for /F %j in ('type "texttest.
txt" | find /V /C ""') do set Full=%j
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Full=567
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set stopvar= ON THIS FORM IS C
OMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Split=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>echo ON THIS FORM IS COMPLETE
AND CORRECT AS NOTED:___________________
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set X=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>type nul 1>"C:\Users\theangry
asiancp\Desktop\RRRR_Split_Test\texttest_!X!.new"
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set N=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Q=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set S=0
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set L=63
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>
What are your thoughts? Where am I going wrong with the batch? I wish I could use something different, but alas I cannot, for internal company reasons. Thanks for your help!
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "name=q23396663"
SET "ext=.txt"
SET /a pagelength=10
SET "targetstring= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
SET /a filenum=0
SET /a linecount=pagelength + 1
FOR /f "tokens=1*delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
IF !linecount! GEQ %pagelength% (
SET /a linecount=0
SET /a filenum+=1
)
>>U:\%name%_!filenum!.new ECHO(%%b
IF "%%b"=="%targetstring%" SET /a linecount=pagelength
SET /a linecount+=1
)
GOTO :EOF
For testing purposes, I set up a file q23396663.txt containing your trigger data. I've left the destination directory as U:\ which suits me, and the pagelength at 10 which makes my testing easier.
#echo off
setlocal EnableDelayedExpansion
REM ------------------THIS SECTION SPECIFIES THE FILE-------------------------
set param=%*
if not defined param (
echo.
echo. Usage: filesplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
GOTO :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
ECHO SPLITTING %name%.%ext% .................
REM ----------------THIS SECTION SETS THE VARIABLES---------------------------
set "trigger= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
set /a pagelength=63
set /a filenum=0
set split=1
set /a linecount=pagelength
set stopvar=0
REM ------------------THIS SECTION IS THE FOR LOOP----------------------------
FOR /f "skip=2 tokens=1* delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
SET /a linecount-=1
IF !linecount! LEQ 0 (
IF !stopvar! EQU 1 (
SET /a "linecount=pagelength"
SET /a filenum+=1
SET /a split+=1
SET /a stopvar-=1
) else set /a "linecount=pagelength"
)
echo.%%b>> "%name%_!filenum!.new"
IF "%%b"=="%trigger%" (
set /a "stopvar+=1"
REM THIS TRIGGERS TO CHANGE OUTPUT
set /a linecount+=1
REM THIS WILL ADJUST THE OUTPUT EOF
)
)
REM ----------------THIS SECTION ENDS THE FOR LOOP----------------------------
ECHO Split into %split% files!
ping 1.1.1.1 -n 1 -w 2500 > nul
REM THIS PAUSES THE BATCH FOR A SEC
As I posted in the comment above, this is just a variation of the first answer that accounts for blank spaces if they are needed to keep the output files from having unnecessary whitespace on top. This is especially helpful when a print manager is just spitting out whitespace until the end of the page before starting the next part instead of going straight to the next portion.

Using an if statement inside a for loop

I am trying to make a batch file to solve the first Project Euler problem, http://projecteuler.net/problem=1, but I need an if statement inside my loop to check if n modulo 3 or 5 is 0. And the sum has suddenly stopped working.
My code:
echo off
set sum=0
for /l %%n in (1,1,999) do (
set a/ sum+=%%n *(only add if n%%3 == 0 or n%%5 == 0)*
)
echo %sum%
pause
Here is a very efficient solution, though it is a bit obfuscated:
#echo off
setlocal
set /a sum=0
for /l %%N in (1 1 999) do set /a "sum+=%%N/!((%%N%%5)*(%%N%%3))" 2>nul
echo %sum%
The expression (%%N%%5)*(%%N%%3) yields zero if %%N is divisible by 3 or 5, or non-zero if it is not divisible by either. The ! takes the inverse logical value, so 0 becomes 1, and non-zero becomes 0. Dividing %%N by that expression yields either %%N or a division by zero error. So simply add that entire expression to the sum, and redirect error messages to nul.
Final result - only numbers divisible by 3 or 5 are added :-)
#ECHO OFF
SETLOCAL
set /A sum=0
for /l %%n in (1,1,999) do (
CALL :modulo %%n
IF DEFINED addme set /a sum+=%%n
REM CALL echo %%n %%sum%% %%addme%%
)
echo %sum%
GOTO :EOF
:modulo
:: set addme if %1 %% 3 == 0 or %1 %% 5 == 0
SET /a addme = %1 %% 3
IF %addme%==0 GOTO :EOF
SET /a addme = %1 %% 5
IF %addme%==0 GOTO :EOF
SET "addme="
GOTO :eof
Simply pass each value to the :modulo routine in turn and set a flag value to (clear or not)
OR
#ECHO OFF
SETLOCAL enabledelayedexpansion
set /A sum=0
for /l %%n in (1,1,999) do (
SET /a mod=%%n %% 3
IF NOT !mod!==0 SET /a mod=%%n %% 5
IF !mod!== 0 set /a sum+=%%n
rem CALL echo %%n %%sum%%
)
echo %sum%
GOTO :EOF
which does the same thing using delayedexpansion.
And the sum has suddenly stopped working.
I think your sum stopped working because your set needs to have the slash in front of the 'a', and not behind it, like this:
SET /A sum+=%%n
Also, there isn't an OR operator in DOS Batch, so you'll need to use a nested IF for that. This worked for me:
echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set sum=0
for /l %%n in (1,1,999) do (
SET /A mod3=%%n%%3
SET /A mod5=%%n%%5
IF !mod3!==0 (
SET /A sum+=%%n
) ELSE (
IF !mod5!==0 (
SET /A sum+=%%n
)
)
)
echo %sum%
ENDLOCAL
If you need more help, check out Rob van der Woude's Scripting pages. Specifically, here is a link to his page on performing mathematical operations in DOS batch files.

Removing non alphanumeric characters in a batch variable

In batch, how would I remove all non alphanumeric (a-z,A-Z,0-9,_) characters from a variable?
I'm pretty sure I need to use findstr and a regex.
The solutionof MC ND works, but it's really slow (Needs ~1second for the small test sample).
This is caused by the echo "!_buf!"|findstr ... construct, as for each character the pipe creates two instances of cmd.exe and starts findstr.
But this can be solved also with pure batch.
Each character is tested if it is in the map variable
:test
set "_input=Th""i\s&& is not good _maybe_???"
set "_output="
set "map=abcdefghijklmnopqrstuvwxyz 1234567890"
:loop
if not defined _input goto endLoop
for /F "delims=*~ eol=*" %%C in ("!_input:~0,1!") do (
if "!map:%%C=!" NEQ "!map!" set "_output=!_output!%%C"
)
set "_input=!_input:~1!"
goto loop
:endLoop
echo(!_output!
And it could be speed up when the goto loop is removed.
Then you need to calculate the stringLength first and iterate then with a FOR/L loop over each character.
This solution is ~6 times faster than the above method and ~40 times faster than the solution of MC ND
set "_input=Th""i\s&& is not good _maybe_!~*???"
set "_output="
set "map=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890"
%$strLen% len _input
for /L %%n in (0 1 %len%) DO (
for /F "delims=*~ eol=*" %%C in ("!_input:~%%n,1!") do (
if "!map:%%C=!" NEQ "!map!" set "_output=!_output!%%C"
)
)
exit /b
The macro $strlen can be defined with
set LF=^
::Above 2 blank lines are required - do not remove
#set ^"\n=^^^%LF%%LF%^%LF%%LF%^^":::: StrLen pResult pString
set $strLen=for /L %%n in (1 1 2) do if %%n==2 (%\n%
for /F "tokens=1,2 delims=, " %%1 in ("!argv!") do (%\n%
set "str=A!%%~2!"%\n%
set "len=0"%\n%
for /l %%A in (12,-1,0) do (%\n%
set /a "len|=1<<%%A"%\n%
for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"%\n%
)%\n%
for %%v in (!len!) do endlocal^&if "%%~b" neq "" (set "%%~1=%%v") else echo %%v%\n%
) %\n%
) ELSE setlocal enableDelayedExpansion ^& set argv=,
EDITED - #jeb is right. This works but is really, really slow.
#echo off
setlocal enableextensions enabledelayedexpansion
set "_input=Th""i\s&& is not good _maybe_???"
set "_output="
:loop
if not defined _input goto endLoop
set "_buf=!_input:~0,1!"
set "_input=!_input:~1!"
echo "!_buf!"|findstr /i /r /c:"[a-z 0-9_]" > nul && set "_output=!_output!!_buf!"
goto loop
:endLoop
echo !_output!
endlocal
So, back to the drawing board. How to make it faster? lets try to do as less operations as we can and use as much long substring as we can. So, do it in two steps
1.- Remove all bad characters that can generate problems. To do it we will use the hability of for command to identify these chars as delimiters , and then join the rest of the sections of god characters of string
2.- Remove the rest of the bad characters, locating them in string using the valids charactes as delimiters to find substrings of bad characters, replacing then in string
So, we end with (sintax adapted to what has been answered here)
#echo off
setlocal enableextensions enabledelayedexpansion
rem Test empty string
call :doClean "" output
echo "%output%"
rem Test mixed strings
call :doClean "~~asd123#()%%%^"^!^"~~~^"""":^!!!!=asd^>^<bm_1" output
echo %output%
call :doClean "Thi\s&& is ;;;;not ^^good _maybe_!~*???" output
echo %output%
rem Test clean string
call :doClean "This is already clean" output
echo %output%
rem Test all bad string
call :doClean "*******//////\\\\\\\()()()()" output
echo "%output%"
rem Test long string
set "zz=Thi\s&& is not ^^good _maybe_!~*??? "
set "zz=TEST: %zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%"
call :doClean "%zz% TEST" output
echo %output%
rem Time long string
echo %time%
for /l %%# in (1 1 100) do call :doClean "%zz%" output
echo %time%
exit /b
rem ---------------------------------------------------------------------------
:doClean input output
setlocal enableextensions enabledelayedexpansion
set "map=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 "
set "input=%~1"
set "output="
rem Step 1 - Remove critical delimiters
(
:purgeCritical
for /L %%z in (1 1 10) do (
for /f tokens^=1^-9^,^*^ delims^=^=^"^"^~^;^,^&^*^%%^:^!^(^)^<^>^^ %%a in ("!input!") do (
set "output=!output!%%a%%b%%c%%d%%e%%f%%g%%h%%i"
set "input=%%j"
)
if not defined input goto outPurgeCritical
)
goto purgeCritical
)
:outPurgeCritical
rem Step 2 - remove any remaining special character
(
:purgeNormal
for /L %%z in (1 1 10) do (
set "pending="
for /f "tokens=1,* delims=%map%" %%a in ("!output!") do (
set "output=!output:%%a=!"
set "pending=%%b"
)
if not defined pending goto outPurgeNormal
)
goto purgeNormal
)
:outPurgeNormal
endlocal & set "%~2=%output%"
goto :EOF
Maybe not the fastest, but at least a "decent" solution
#echo eof
call :purge "~~asd123#()%%%^"^!^"~~~^:^=asd^>^<bm_1" var
echo (%var%)
goto :eof
:purge StrVar [RtnVar]
setlocal disableDelayedExpansion
set "str1=%~1"
setlocal enableDelayedExpansion
for %%a in ( - ! # # $ % ^^ ^& + \ / ^< ^> . ' [ ] { } ` ^| ^" ) do (
set "str1=!str1:%%a=!"
)
rem dealing with some delimiters
set "str1=!str1:(=!"
set "str1=!str1:)=!"
set "str1=!str1:;=!"
set "str1=!str1:,=!"
set "str1=!str1:^^=!"
set "str1=!str1:^~=!"
set "temp_str="
for %%e in (%str1%) do (
set "temp_str=!temp_str!%%e"
)
endlocal & set "str1=%temp_str%"
setlocal disableDelayedExpansion
set "str1=%str1:!=%"
set "str1=%str1::=%"
set "str1=%str1:^^~=%"
for /f "tokens=* delims=~" %%w in ("%str1%") do set "str1=%%w"
endlocal & set "str1=%str1%"
endlocal & if "%~2" neq "" (set %~2=%str1%) else echo %str1%
goto :eof
Still cannot deal with ~ and = but working on it
EDIT: = now will be cleared
EDIT: ~ now will be cleared

Resources