Puzzling Batch String Slicing Error - string

So I am creating a program that separates numbers and letters into 2 different variables so it turns "word1234" into a variable containing "word" and a variable containing "1234", what I did was make a program that runs through a variable "info" letter by letter. "Is it a number?" "No", "Is It a letter?" "Yes". When the variable "toggle" was still on the value 0, it would carry on appending the letters to the "weatherd" variable and else append it to the "temperat" variable.
Note: I know my variable and label names are bad, I come up with them in about half a second :)
So it checks if it is a number, if it is the "toggle" variable changes to a 1 and it starts putting the rest of the text into a new variable ("temperat"). I was wondering, once it hits the numbers it gives me an error and crashes, why? Or is there a simpler way than what I'm doing?
Sorry for the massive post, I added some pauses and stuff for debugging, code here:
REM PREPARE FOR A MASSIVE AMOUNT OF CODE, all this stuff just gets the current weather, ignore it
#echo off
set "wherestay=%cd%"
cd /d C:
cd\
cd "C:/Users/%USERNAME%/Downloads"
del weather.txt
start chrome.exe teamhaxor.netau.net/getWeather.php
set times=0
:loading
set /a times=%times% + 1
if %times% == 2000 goto failed
if not exist weather.txt goto loading
cd /d C:
cd\
cd "C:/Users/%USERNAME%/Downloads"
< weather.txt (
set /p info=
)
REM PROBLEM STARTS HERE
setlocal enabledelayedexpansion
#echo on
set tempery=0
set "weatherd="
set "temperat="
set toggle=0
:loopy
set "char=!info:~%tempery%, 1!"
if "%char%" EQU "0" set toggle=1
if "%char%" EQU "1" set toggle=1
if "%char%" EQU "2" set toggle=1
if "%char%" EQU "3" set toggle=1
if "%char%" EQU "4" set toggle=1
if "%char%" EQU "5" set toggle=1
if "%char%" EQU "6" set toggle=1
if "%char%" EQU "7" set toggle=1
if "%char%" EQU "8" set toggle=1
if "%char%" EQU "9" set toggle=1
pause
if %toggle% EQU 0 (set weatherd=%weatherd%%char%) ELSE (set temperat=%temperat%%char%)
pause
set /a tempery=%tempery% + 1
pause
if %tempery% EQU 15 (goto out) ELSE (goto loopy)
:out
echo %weatherd%
echo %temperat%
setlocal disabledelayedexpansion
REM PROBLEM STOPS HERE
goto afterafterlol
:failed
set weatherd=Failed
set temperat=Failed
:afterafterlol
cd /d C:
cd\
cd %wherestay%
echo %weatherd%
echo %temperat%
pause >Nul

To answer your question directly, there's an easier way to split your value so that you end up with alpha in one variable and numeric in another.
Treat numbers as delimiters, thereby removing them without having to know specifically which numbers will occur. This will leave you with only the alphabetic portion of the value.
Remove the alphabetic portion from the whole, leaving you with the numeric porition.
#echo off & setlocal
set "var=Thunderstorms87"
for /f "delims=0123456789" %%I in ("%var%") do set "condition=%%~I"
call set "temperature=%%var:%condition%=%%"
echo %condition%
echo %temperature%
In a broader sense, your project seems like a very cumbersome way to scrape not a lot of useful data. It would be better to query a weather service that offers an API with a structured response that doesn't require splitting strings or other flat text hacks.
Here's an example script that uses Weather Underground's API, retrieving and parsing its JSON response. You'll need to create an account and sign up for a free API key, but you get so much more data and it's so much easier to parse. And there's no need to spawn a Chrome window to fetch your data this way.
#if (#CodeSection == #Batch) #then
#echo off & setlocal
rem // weather.bat
rem // https://stackoverflow.com/a/44015647/1683264
rem // go to https://www.wunderground.com/weather/api/ for an API key
set "APIkey=pasteyourAPIkeyhere"
if "%~1"=="" ( set "location=autoip" ) else set "location=%~1"
cscript /nologo /e:JScript "%~f0" "%APIkey%" "%location%"
rem // end main runtime
goto :EOF
#end // end batch / begin JScript chimera
var x = WSH.CreateObject("Microsoft.XMLHTTP"),
htmlfile = WSH.CreateObject('htmlfile'),
APIkey = WSH.Arguments(0),
loc = WSH.Arguments(1),
URL = 'http://api.wunderground.com/api/' + APIkey + '/conditions/q/' + loc + '.json',
JSON = obj = {}, pad = ' ';
htmlfile.write('<meta http-equiv="x-ua-compatible" content="IE=9" />');
htmlfile.close(JSON = htmlfile.parentWindow.JSON);
x.open("GET", URL, true);
x.setRequestHeader('User-Agent','XMLHTTP/1.0');
x.send('');
while (x.readyState!=4) {WSH.Sleep(50)};
response = JSON.parse(x.responseText).current_observation;
obj = {
"station": response.observation_location.full,
"timestamp": response.observation_time,
"conditions": response.weather,
"temperature": response.temperature_string,
"humidity": response.relative_humidity,
"wind": response.wind_string,
"heat index": response.heat_index_string,
"wind chill": response.windchill_string,
"forecast URL": response.forecast_url
};
for (var i in obj) while (i.length > pad.length) pad += ' '
for (var i in obj) {
var key = (i + pad).substring(0, pad.length);
WSH.Echo(key + ' : ' + obj[i]);
}
Output looks something like this:
You can use something like:
WSH.Echo(x.responseText);
... to view the raw JSON and see all the other data included in the feed. You can also modify the URL and replace conditions with forecast, hourly, and a bunch of other options (as well as replacing current_observation and the response object properties as appropriate).

Related

Replace Uppercase and Lowercase separately in a String

I would like to get this batch to work as expected, but it is not able to detect the upper and lower casing (I do not know how). So here is the thing:
#echo off
set /p letter="write letter: "
set var=%letter%
set result1=%var:M=7%
set result2=%result1:m=8%
echo %result2%
pause > nul
exit
for now:
When I write "M" in the letter variable, i get 7
When I write "m" in the letter variable, i get 7 also (because it is already converted)
what i want:
when i write "M" i get 7
when i write "m" i get 8
when i write "Mm" i get 78
any help with that? I would like to keep it simple as I am new at this, thanks
#ECHO Off
SETLOCAL
SET "string=string containing M and m"
SET "newstring="
:loop
IF DEFINED string (
IF "%string:~0,1%" == "M" (
SET "Newstring=%newstring%7"
) ELSE (
IF "%string:~0,1%" == "m" (
SET "Newstring=%newstring%8"
) ELSE (
SET "Newstring=%newstring%%string:~0,1%"
)
)
SET string
SET "string=%string:~1%"
GOTO loop
)
ECHO newstring=%newstring%
GOTO :EOF
Characters that have a special meaning to cmd ("Poison characters") will probably cause problems.

replace unneeded spaces with commas in txt using batch

I have a text file that contains some information and looks like this:
7253 198760.294 533963.581
7373 198752.213 533954.046
739CT 198751.288 533952.902
In every line there are parameters that has spaces between them but the spaces (not tabs) are for ease or reading only.
I need it to look like this:
1550,168040.682,630305.751,
1575,168023.241,630287.837,
15964TS,168008.317,630272.508,
Here is my code:
#echo off
setlocal EnableDelayedExpansion
set LF=^
set "content="
for /f "delims=" %%x in (input.txt) do (
set "content=!content!%%x!LF!"
)
:loop
if defined content (
set "new=!content: = !"
if "!new!" neq "!content!" (
set "content=!new!"
goto :loop
)
)
if defined content if "!str:~0,1!" equ " " set "content=!str:~1!"
if defined content if "!str:~-1!" equ " " set "content=!str:~0,-1!"
echo(!content!
set string=!content! & echo !string: =,! > output.txt
endlocal
pause > null
It turns everything in one line and connects between everything without spaces.
Concatenation to a single string is dangerous, because of limited max string length. Better process each line on it's own:
(for /f "tokens=1-3" %%a in (infile.txt) do (
echo %%a,%%b,%%c,
))>outfile.txt
note: empty lines will be ignored (will get lost)

How to generate string for bruteforce attack using batchfile

I have some code which can crack numeric rar file passwords. The code just increments the value of a variable (starting from 0) and I use that to check against the password to unrar using unrar command.
But I want to generate strings for brute force attacks.
SET PASSWORD=0
:START
SET /A PASSWORD=%PASSWORD%+1
UNRAR E -INUL -P%PASSWORD% "%PATH%\%NAME%" "%DESTINATION%"
IF /I %ERRORLEVEL% EQU 0 GOTO CLOSE
GOTO START
:CLOSE
echo Password Cracked...
echo Password is %PASSWORD%
Here
%PATH% is path where rar file is located
%NAME% is name of rar file
%DESTINATION% is place where file is stored after UNRAR,
In my code DESTINATION is "%TEMP%\%RANDOM%"
By applying this I am able to get the password, but it is not useful for strings which contain alpha characters.
How do I generate strings starting from "a", so I am able to crack alphabetic passwords too?
I consider this a crazy idea to do in CMD/batch, but it at least sounded like an interesting challenge.
So, playing the part of the Professor from Gilligan's Island, I've decided to attempt to build a particle accelerator from coconuts.
Here's my entry. There might likely be a better solution using CMD/batch. The most favorable thing I can say about it is that it works. To adapt it to your purpose, change the ECHO statement inside the :INFINITE_LOOP to do something meaningful, like attempt to decompress the file and exit on success.
Here's a sample of the output as it runs:
'0'
'1'
...
'9'
...
'A'
'B'
...
'Y'
'Z'
'a'
'b'
...
'y'
'z'
'00'
'01'
...
'zy'
'zz'
'000'
'001'
...
'Car'
'Cas'
'Cat'
'Cau'
'Cav'
'Caw'
...
This solution should work with many characters (CHARSET contains all the characters to be used in the output string) with the exception of characters that cannot be assigned simply without escaping them in some manner (e.g. double quote, percent (maybe?), exclamation, ...).
The script doesn't completely clean up after itself (you'll have to manually erase %ITER_FILE%), but it isn't too messy.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "CHARSET=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghikjlmnopqrstuvwxyz"
:: ======================================================================
:: Setup
CALL :CONFIGURE_CHARSET "%CHARSET%"
REM ECHO MAX_INDEX: !MAX_INDEX!
REM SET
:: Put the smallest value in the file.
SET ITER_FILE=%TEMP%\ITERATOR_%RANDOM%.txt
ECHO.0>"%ITER_FILE%"
:: ======================================================================
:: Main Loop
:INFINITE_LOOP
CALL :READ_ITER "%ITER_FILE%" _ITER_CONTENTS
ECHO '!_ITER_CONTENTS!'
CALL :NEXT_ITER "%ITER_FILE%"
GOTO :INFINITE_LOOP
EXIT /B
:: "Increment" the contents of the "state variable" file.
:NEXT_ITER
SETLOCAL
SET "FILE=%~1"
SET "NEXT_FILE=%TEMP%\ITERATOR_NEXT_%RANDOM%.txt"
SET CARRY=1
FOR /F %%n IN (%FILE%) DO (
IF !CARRY! EQU 1 (
SET /A I_VALUE=%%n+1
IF !I_VALUE! GTR %MAX_INDEX% (
SET I_VALUE=0
SET CARRY=1
) ELSE (
SET CARRY=0
)
) ELSE (
SET I_VALUE=%%n
)
ECHO !I_VALUE!>>"!NEXT_FILE!"
)
REM Add a new digit place.
IF !CARRY! EQU 1 (ECHO.0>>"!NEXT_FILE!")
MOVE /Y "%NEXT_FILE%" "%FILE%" >NUL
ENDLOCAL
EXIT /B
:: Read the contents of the "state variable" file and translate it
:: into a string.
:: The file is a series of lines (LSB first), each containing a single
:: number (an index).
:: Each index represents a single character from the CHARSET.
:READ_ITER
SETLOCAL
SET "FILE=%~1"
SET "VAR=%~2"
SET VALUE=
SET _V=
FOR /F %%n IN (%FILE%) DO (
SET "VALUE=!VALUE_%%n!!VALUE!"
)
ENDLOCAL && SET %VAR%=%VALUE%
EXIT /B
:: Translate the index number to a character.
:TRANS_INDEX
SETLOCAL
SET "VAR=%~1"
SET "C=%~2"
SET IDX=
FOR /L %%i IN (0,1,%MAX_INDEX%) DO (
IF "!VALUE_%%i!"=="!C!" SET IDX=%%i
)
SET "TRANS=!VALUE_%%i!"
ENDLOCAL && SET "%VAR%=%TRANS%"
EXIT /B
:: This is ugly magic.
:: Create variables to hold the translation of an index to a character.
:: As a side effect, set MAX_INDEX to the largest used index.
:CONFIGURE_CHARSET
SET CONFIG_TEMP=%TEMP%\CONFIG_%RANDOM%.cmd
IF EXIST "%CONFIG_TEMP%" DEL /Q "%CONFIG_TEMP%"
CALL :WRITE_CONFIG "%CONFIG_TEMP%" "%~1"
REM Import all the definitions.
CALL "%CONFIG_TEMP%"
EXIT /B
REM Create a means to "add one" to a value.
:WRITE_CONFIG
SETLOCAL
SET "FILE=%~1"
SET "STR=%~2"
REM This is the "index" of the symbol.
SET "INDEX=%~3"
IF "!INDEX!"=="" SET INDEX=0
IF NOT "%STR%"=="" (
SET "C=!STR:~0,1!"
IF NOT "%~4"=="" (
SET "FIRST=%~4"
) ELSE (
SET "FIRST=!C!"
)
SET "D=!STR:~1,1!"
IF "!D!"=="" (
SET CARRY=1
SET "D=!FIRST!"
) ELSE (
SET CARRY=0
)
ECHO SET VALUE_!INDEX!=!C!>>"!FILE!"
SET /A NEXT_INDEX=INDEX+1
REM Recurse...
SET MAX_INDEX=!INDEX!
CALL :WRITE_CONFIG "!FILE!" "!STR:~1!" "!NEXT_INDEX!" "!FIRST!"
IF !INDEX! GTR !MAX_INDEX! SET MAX_INDEX=!INDEX!
)
ENDLOCAL && SET MAX_INDEX=%MAX_INDEX%
EXIT /B
Recursion does the job!
I know I'm a bit late, but I think this code works very well and also quite fast:
#echo off
title bruteforce
setlocal enableDelayedExpansion
echo:
echo Brute Force Attack:
echo -------------------
echo:
set /p input="Amount of digits: "
set /a depth=%input%-1
echo:
set /p possibleChars="Possible Characters: "
echo:
for /l %%y in (0, 1, %depth%) do (
set chars[%%y]=0
)
call :next 0
echo:
pause
exit
:next
setLocal
set /a d=%1
for %%x in (%possibleChars%) do (
set chars[%d%]=%%x
if %d% lss %depth% (
call :next !d!+1
) else (
set password=
for /l %%c in (0, 1, %depth%) do (
set password=!!password!!chars[%%c]!!
)
echo !password!
)
)
On my laptop it prints about 1500 combinations per second, and you can do what ever you want with the password-variable which I've just printed out!
IMPORTANT:
The first part of the program asks you for the length of the password to crack and possible characters when you run it!
You have to enter the possible characters with a space between each character, like this:
0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k...

How to split string in a variable without loosing spaces?

how can i split the string
" This is a text with spaces "
that is in the variable "string"
into text parts without loosing the spaces ?
set string="# This is a text with spaces #"
should be split into
"# This"
" is"
" a"
" text"
" with"
" spaces #"
Using For /F "delims= " ... doesn't work because it eliminates all spaces.
Is there a 'simple' solution or can anyone explain how to parse the string character by character
so i can count up spaces to first character, then read all characters until next space and write
the counted spaces and the read characters together to a new/temp variable ??
thanks
Yeah, I don't really understand the # either. What is it about " spaces #" that makes it hold onto the trailing spaces, while all other elements keep the preceding but not the proceeding spaces?
Oh, well, effort spent in asking = effort spent in answering. Do with this what you will.
#if (#a==#b) #end /*
:: batch portion
#echo off
setlocal
call :split "# This is a text with spaces #"
exit /b
:split <string>
cscript /nologo /e:jscript "%~f0" "%~1"
goto :EOF
:: JScript portion */
WSH.Echo(WSH.Arguments(0).match(/\s*\S+/g).join('\n'));
Output:
#
This
is
a
text
with
spaces
#
Update
If you want the first + second, and the penultimate + ultimate elements joined, modify the JScript portion of the above script as follows:
:: JScript portion */
var m = WSH.Arguments(0).match(/\s*\S+/g);
m[0] = m.shift() + m[0];
m[m.length - 2] += m.pop();
WSH.Echo(m.join('\n'));
Output:
# This
is
a
text
with
spaces #
And if you want each element enclosed in quotation marks, change the last line as follows:
WSH.Echo('"' + m.join('"\n"') + '"');
Output:
"# This"
" is"
" a"
" text"
" with"
" spaces #"
I don't see a simple solution in batch, though of course if you can consider powershell or javascript you'll be working with a more appropriate toolset for string manipulation.
Sticking with the batch requirement, you can loop through character by character and "collect" your words with something like this:
#echo off
setlocal enabledelayedexpansion
set "string= This is a text with spaces "
set idx=0
set "word="
set "char="
set "lastchar= "
:loop
if "!string:~%idx%!" equ "" goto :eof
set char=!string:~%idx%,1!
if "%char%" equ " " (
if "%lastchar%" neq " " (
echo [%word%]
set word=%char%
) else (
set word=%word%%char%
)
) else (
set word=%word%%char%
)
set lastchar=%char%
set /a idx=%idx%+1
goto loop
This script uses batch's substring feature !string:~%idx%,1 to grab a single character from the string, incrementing idx with each loop. Then it's just a matter of processing the word (echo in this example) when the previous character was not a space and the current one is.
This writes out:
[ This]
[ is]
[ a]
[ text]
[ with]
[ spaces]
Note that I'm ignoring the # you had in your example because I don't understand where they fit in.
the trick is substituting the contiguous spaces by just one space and the rest by some arbitrary character. Assuming your string does not contain #s and that there are no more than 9 contiguous spaces, you can try this
set st=%st: = ########%
set st=%st: = #######%
set st=%st: = ######%
set st=%st: = #####%
set st=%st: = ####%
set st=%st: = ###%
set st=%st: = ##%
set st=%st: = #%
then you may parse with for /f and substitute back your #s by spaces
setlocal enabledelayedexpansion
for /f %%a in ("%st%") do (
set ss= %%a
echo !ss:#= !
)
note that set inside the parentheses block requires you to enable delayed expansion and to use the ! syntax (see HELP SET)
But this technique will only extract the first substring. To generalize, you need another trick, that is substituting the spaces into newlines so that the for /f will loop kinda line by line
note that in order to obtain a newline char you need to preserve the two blank lines after the set command
set nl=^
rem continue two lines down....
for /f %%a in ("%st: =!nl!%") do (
set ss= %%a
set ss=!ss:#= !
echo [!ss!]
)
Try this:
#echo off &setlocal enabledelayedexpansion
set "string=# This is a text with spaces #"
set string1=%string%
for %%i in (%string%) do (
set string1=!string1: %%i = "%%i" !
set /a strings+=1
)
set string1=#"%string1:~1,-1%"#
set string1=%string1:"= "%
for %%i in (%string1%) do (
set /a count+=1
set string2=%%i
set string2=!string2: "=!
set string2=!string2:"=!
if !count! equ 2 (
set $s1=!$s1!!string2!
)else if !count! equ %strings% (
set /a count-=1
call set $s!count!=%%$s!count!%%!string2!
) else set $s!count!=!string2!
)
for /f "tokens=1*delims==" %%i in ('set "$s"') do echo "%%j"
Output:
"# This"
" is"
" a"
" text"
" with"
" spaces #"
If I had to accomplish this obscure task, I would use a hybrid JScript/batch technique like in rojo's answer. However, I would use a REPL.BAT utility that I have already written. Assuming my REPL.BAT is in either the current folder, or else somewhere in the PATH, then the following will work:
#echo off
setlocal enableDelayedExpansion
set "string=# This is a text with spaces #"
:: Build an "array" of text parts
set cnt=0
for /f delims^=^ eol^= %%A in ('repl "([^ ])(?= )" "$1\n" xs string') do (
set /a cnt+=1
set "string!cnt!=%%A"
)
:: Print the array values
for /l %%N in (1 1 %cnt%) do echo string%%N=[!string%%N!]
But if I wanted a pure batch solution, I would use the fairly efficient method below:
#echo off
setlocal enableDelayedExpansion
set "string=# This is a text with spaces #"
:: Define LF to contain a single line feed character (0x0A)
set LF=^
:: Above 2 blank lines are critical - DO NOT REMOVE
:: Insert a line feed before every space
for %%n in ("!LF!") do set "string=!string: =%%~n !"
:loop Remove line feeds sandwiched by spaces
for %%n in ("!LF!") do set "string2=!string: %%~n = !"
if "!string2!" neq "!string!" (
set "string=!string2!"
goto :loop
)
:: Build an "array" of text parts: FOR /F splits the string at line feeds
set /a cnt=0
for /f delims^=^ eol^= %%A in ("!string!") do (
set /a cnt+=1
set "string!cnt!=%%A"
)
:: Print out the array values
for /l %%N in (1 1 %cnt%) do echo string%%N=[!string%%N!]
Both solutions above give the following output:
string1=[#]
string2=[ This]
string3=[ is]
string4=[ a]
string5=[ text]
string6=[ with]
string7=[ spaces]
string8=[ #]
Note that the FOR loop %%A expansion will corrupt the results if the string contains ! due to delayed expansion. This limitation can be eliminated with additional coding. All the other posted solutions that use a FOR loop suffer from this same limitation. (at least they did when I wrote this)

Batch file: How to replace "=" (equal signs) and a string variable?

Besides SED, how can an equal sign be replaced?
And how can I use a string variable in string replacement?
Consider this example:
For /F "tokens=*" %%B IN (test.txt) DO (
SETLOCAL ENABLEDELAYEDEXPANSION
SET t=is
SET old=%%B
SET new=!old:t=!
ECHO !new!
ENDLOCAL
)
:: SET new=!old:==!
Two problems:
First, I cannot use the variable %t% in !:=!.
SET t=is
SET old=%%B
SET new=!old:t=!
Second, I cannot replace the equal sign in the command line
SET new=!old:==!
I just created a simple solution for this myself, maybe it helps someone.
The disadvantage (or advantage, depends on what you want to do) is that multiple equal signs one after another get handled like one single equal sign. (example: "str==ing" gives the same output as "str=ing")
#echo off
set "x=this is=an test="
echo x=%x%
call :replaceEqualSign in x with _
echo x=%x%
pause&exit
:replaceEqualSign in <variable> with <newString>
setlocal enableDelayedExpansion
set "_s=!%~2!#"
set "_r="
:_replaceEqualSign
for /F "tokens=1* delims==" %%A in ("%_s%") do (
if not defined _r ( set "_r=%%A" ) else ( set "_r=%_r%%~4%%A" )
set "_s=%%B"
)
if defined _s goto _replaceEqualSign
endlocal&set "%~2=%_r:~0,-1%"
exit /B
As you have seen, you use the function like this:
call :replaceEqualSign in variableName with newString
The setlocal enableDelayedExpansion should be moved after your old=%%B assignment in case %%B contains !.
The "t" problem is easy to solve within a loop by using another FOR variable
For /F "tokens=*" %%B IN (test.txt) DO (
SET t=is
SET old=%%B
SETLOCAL ENABLEDELAYEDEXPANSION
for /f %%T in ("!t!") do SET new=!old:%%T=!
ECHO !new!
ENDLOCAL
)
There is no simple native batch solution for replacing =. You can iterate through the string, character by character, but that is slow. Your best bet is probably to switch to VBScript or JScript, or use a non-native utility.
If you really want to do this using pure Windows batch commands, there are a couple of interesting ideas at http://www.dostips.com/forum/viewtopic.php?t=1485
UPDATE: The latest version is here: https://github.com/andry81/contools (https://github.com/andry81/contools/tree/HEAD/Scripts/Tools/std/)
You can use some sequence to temporary replace special characters by placeholders like ?00, ?01, ?02 and ?03. I basically use these set of scripts:
replace_sys_chars.bat:
#echo off
rem Description:
rem Script to replace ?, !, %, and = characters in variables by respective
rem ?00, ?01, ?02 and ?03 placeholders.
setlocal DISABLEDELAYEDEXPANSION
set "__VAR__=%~1"
if "%__VAR__%" == "" exit /b 1
rem ignore empty variables
call set "STR=%%%__VAR__%%%"
if "%STR%" == "" exit /b 0
set ?01=!
call set "STR=%%%__VAR__%:?=?00%%"
set "STR=%STR:!=?01%"
setlocal ENABLEDELAYEDEXPANSION
set STR=!STR:%%=?02!
set "STR_TMP="
set INDEX=1
:EQUAL_CHAR_REPLACE_LOOP
set "STR_TMP2="
for /F "tokens=%INDEX% delims== eol=" %%i in ("/!STR!/") do set STR_TMP2=%%i
if "!STR_TMP2!" == "" goto EQUAL_CHAR_REPLACE_LOOP_END
set "STR_TMP=!STR_TMP!!STR_TMP2!?03"
set /A INDEX+=1
goto EQUAL_CHAR_REPLACE_LOOP
:EQUAL_CHAR_REPLACE_LOOP_END
if not "!STR_TMP!" == "" set STR=!STR_TMP:~1,-4!
(
endlocal
endlocal
set "%__VAR__%=%STR%"
)
exit /b 0
restore_sys_chars.bat:
#echo off
rem Description:
rem Script to restore ?, !, %, and = characters in variables from respective
rem ?00, ?01, ?02 and ?03 placeholders.
setlocal DISABLEDELAYEDEXPANSION
set "__VAR__=%~1"
if "%__VAR__%" == "" exit /b 1
rem ignore empty variables
call set "STR=%%%__VAR__%%%"
if "%STR%" == "" exit /b 0
setlocal ENABLEDELAYEDEXPANSION
set STR=!STR:?02=%%!
set STR=!STR:?03==!
(
endlocal
set "STR=%STR%"
)
set "STR=%STR:?01=!%"
set "STR=%STR:?00=?%"
(
endlocal
set "%__VAR__%=%STR%"
)
exit /b 0
Example:
#echo off
setlocal DISABLEDELAYEDEXPANSION
for /F "usebackq tokens=* delims=" %%i in ("test.txt") do (
set VALUE=%%i
call :PROCESS
)
exit /b 0
:PROCESS
if "%VALUE%" == "" exit /b 0
set "VALUE_=%VALUE%"
call replace_sys_chars.bat VALUE_
rem do variable arithmetic here as usual
if not "%VALUE_:?00=%" == "%VALUE_%" echo."%VALUE%" having ?
if not "%VALUE_:?01=%" == "%VALUE_%" echo."%VALUE%" having !
if not "%VALUE_:?02=%" == "%VALUE_%" echo."%VALUE%" having %%
if not "%VALUE_:?03=%" == "%VALUE_%" echo."%VALUE%" having =
rem restore it
call restore_sys_chars.bat VALUE_
echo "VALUE=%VALUE_%"
echo.---
test.txt:
111/222
AAA=BBB
CCC=%DDD%
EEE=!FFF!
FFF=?00?01?02?03
Result:
"VALUE=111/222"
---
"AAA=BBB" having =
"VALUE=AAA=BBB"
---
"CCC=%DDD%" having %
"CCC=%DDD%" having =
"VALUE=CCC=%DDD%"
---
"EEE=!FFF!" having !
"EEE=!FFF!" having =
"VALUE=EEE=!FFF!"
---
"FFF=?00?01?02?03" having ?
"FFF=?00?01?02?03" having =
"VALUE=FFF=?00?01?02?03"
---
Features:
You can continue use standard batch variable arithmetic between conversions
You can use character placeholders (?00, ?01, ?02, ?03) as plain variable values
Why not use Edlin? I could not find a way to do this with one initial file and no errors from Edlin, but just ignore them with NUL:.
Strangly, the TYPE %0 includes the whole file even if there's an end of file character between the = and !, using TYPE on the batch file after it has run will not work the same way.
#ECHO OFF
GOTO skip
1,1r=!
e
:skip
SET "new==old============="
ECHO %new% > %TEMP%\var.tmp
TYPE %0 > %TEMP%\edlin.tmp
EDLIN %TEMP%\var.tmp < %TEMP%\edlin.tmp > NUL:
SET /P newnew=<%TEMP%\VAR.TMP
ECHO %newnew%
ERASE %TEMP%\VAR.TMP
ERASE %TEMP%\VAR.BAK
ERASE %TEMP%\edlin.tmp
I was looking into this, because I needed to get rid of = in a string like "test=goingon"
I found that calling a next batchfile with test=goingon as parameters, I have parameters 1, "test" and 2, "goingon", in that batchfile.
So:
batchfile 1:
#echo off
call test2.bat test=goingon
batchfile2:
echo arg1: %1
echo arg2: %2
result:
arg1: test
arg2: goingon
I used Bosj's idea to come up with this. It works.
set s=Abra=Cadabra
echo now you see it %s%
call :ReplaceEqual %s%
echo now you don't %s%
exit /b
:ReplaceEqual
set s=%1_%2
exit /b
My answer from another post, but it applies here, too:
There is an alternative that is easier. Instead of passing in a value that contains an equals sign, try something like a colon instead. Then, through the ability to modify that value (the colon), you can convert it back into an equals. Here is an example:
#echo off
set VALUE1=%1
set VALUE2=%VALUE1::==%
echo value1 = %VALUE1%
echo value2 = %VALUE2%
When you run the batch file, call it like this:
C:\>myBatch name:someValue
The output would be:
value1 = name:someValue
value2 = name=someValue
If the name or value contains a space, you will have other issues to address, though. You will need to wrap the entire string in double quotes. But, then you have the issue of needing to get rid of them. This can also be handled, like this:
#echo off
cls
set PARAM=%1
set BASE=%PARAM:"=%
set PAIR=%BASE::==%
rem Either of these two lines will do the same thing - just notice the 'delims'
rem for /f "tokens=1,2 delims=:" %%a in ("%BASE%") do set NAME=%%a & set VALUE=%%b
rem for /f "tokens=1,2 delims==" %%a in ("%PAIR%") do set NAME=%%a & set VALUE=%%b
for /f "tokens=1,2 delims=:" %%a in ("%BASE%") do set NAME=%%a & set VALUE=%%b
echo param = %PARAM%
echo base = %BASE%
echo pair = %PAIR%
echo name = %NAME%
echo value = %VALUE%
When running this batch file like this:
C:\>myBatch "some name:another value"
The output will be:
param = "some name:another value"
base = some name:another value
pair = some name=another value
name = some name
value = another value
Hope that helps others in their quest to win the fight with batch files.
Mike V.

Resources